Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bin/julialauncher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ fn check_channel_uptodate(
})?
.version;

if latest_version != current_version {
if latest_version != current_version && is_interactive() {
eprintln!("The latest version of Julia in the `{}` channel is {}. You currently have `{}` installed. Run:", channel, latest_version, current_version);
eprintln!();
eprintln!(" juliaup update");
Expand Down Expand Up @@ -486,7 +486,7 @@ fn get_julia_path_from_installed_channel(
server_etag,
version: _,
} => {
if local_etag != server_etag {
if local_etag != server_etag && is_interactive() {
if channel.starts_with("nightly") {
// Nightly is updateable several times per day so this message will show
// more often than not unless folks update a couple of times a day.
Expand Down
176 changes: 176 additions & 0 deletions tests/command_update.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use predicates::boolean::PredicateBooleanExt;
use predicates::str::contains;
use serde_json::Value;
use std::fs;

mod utils;
use utils::TestEnv;

Expand Down Expand Up @@ -46,3 +51,174 @@ fn command_update_all_with_alias() {

env.juliaup().arg("update").assert().success();
}

#[test]
fn command_update_outdated_channel() {
let env = TestEnv::new();

env.juliaup().arg("add").arg("1.10").assert().success();
env.juliaup().arg("add").arg("1.10.9").assert().success();

let config_path = env.config_path();
let config_content = fs::read_to_string(&config_path).expect("Failed to read config file");
let mut config: Value = serde_json::from_str(&config_content).expect("Failed to parse config");

// Find the actual version key for 1.10.9 in InstalledVersions
let installed_versions = config["InstalledVersions"]
.as_object()
.expect("InstalledVersions should be an object");

let version_1_10_9_key = installed_versions
.keys()
.find(|k| k.starts_with("1.10.9"))
.expect("Should have 1.10.9 version installed")
.clone();

let channels = config["InstalledChannels"]
.as_object_mut()
.expect("InstalledChannels should be an object");

if let Some(channel_110) = channels.get_mut("1.10") {
if let Some(version) = channel_110.get_mut("Version") {
*version = Value::String(version_1_10_9_key);
}
}

fs::write(
&config_path,
serde_json::to_string_pretty(&config).expect("Failed to serialize config"),
)
.expect("Failed to write config file");

env.juliaup()
.arg("status")
.assert()
.success()
.stdout(contains("1.10").and(contains("Update")));

// Update hints should not appear when using julia noninteractively.
// (ideally we'd test the interactive case too, but that's tricky in CI)
env.julia()
.arg("+1.10")
.arg("--version")
.assert()
.success()
.stderr(
contains("latest version")
.not()
.and(contains("juliaup update").not())
.and(contains("You currently have").not()),
);

env.julia()
.arg("+1.10")
.arg("-e")
.arg("1+1")
.assert()
.success()
.stderr(
contains("latest version")
.not()
.and(contains("juliaup update").not())
.and(contains("You currently have").not()),
);

env.juliaup().arg("update").arg("1.10").assert().success();

let updated_config_content =
fs::read_to_string(&config_path).expect("Failed to read config file after update");
let updated_config: Value =
serde_json::from_str(&updated_config_content).expect("Failed to parse updated config");

let updated_channels = updated_config["InstalledChannels"]
.as_object()
.expect("InstalledChannels should be an object");

let new_version = updated_channels
.get("1.10")
.and_then(|c| c.get("Version"))
.and_then(|v| v.as_str())
.expect("1.10 channel should have a version");

assert!(
new_version.starts_with("1.10.10"),
"Channel 1.10 should have been updated to 1.10.10 (was {})",
new_version
);
}

#[test]
fn command_update_all_outdated_channels() {
let env = TestEnv::new();

env.juliaup().arg("add").arg("1.10").assert().success();
env.juliaup().arg("add").arg("1.10.9").assert().success();
env.juliaup().arg("add").arg("1.11").assert().success();
env.juliaup().arg("add").arg("1.11.1").assert().success();

let config_path = env.config_path();
let config_content = fs::read_to_string(&config_path).expect("Failed to read config file");
let mut config: Value = serde_json::from_str(&config_content).expect("Failed to parse config");

let channels = config["InstalledChannels"]
.as_object_mut()
.expect("InstalledChannels should be an object");

if let Some(channel_110) = channels.get_mut("1.10") {
if let Some(version) = channel_110.get_mut("Version") {
*version = Value::String("1.10.9".to_string());
}
}

if let Some(channel_111) = channels.get_mut("1.11") {
if let Some(version) = channel_111.get_mut("Version") {
*version = Value::String("1.11.1".to_string());
}
}

fs::write(
&config_path,
serde_json::to_string_pretty(&config).expect("Failed to serialize config"),
)
.expect("Failed to write config file");

env.juliaup().arg("update").assert().success();

let updated_config_content =
fs::read_to_string(&config_path).expect("Failed to read config file after update");
let updated_config: Value =
serde_json::from_str(&updated_config_content).expect("Failed to parse updated config");

let updated_channels = updated_config["InstalledChannels"]
.as_object()
.expect("InstalledChannels should be an object");

let new_version_110 = updated_channels
.get("1.10")
.and_then(|c| c.get("Version"))
.and_then(|v| v.as_str())
.expect("1.10 channel should have a version");

let new_version_111 = updated_channels
.get("1.11")
.and_then(|c| c.get("Version"))
.and_then(|v| v.as_str())
.expect("1.11 channel should have a version");

assert!(
new_version_110.starts_with("1.10.10"),
"Channel 1.10 should have been updated to 1.10.10 (was {})",
new_version_110
);

assert!(
new_version_111.starts_with("1.11."),
"Channel 1.11 should have been updated to latest 1.11.x (was {})",
new_version_111
);
assert!(
!new_version_111.starts_with("1.11.1"),
"Channel 1.11 should have been updated past 1.11.1 (was {})",
new_version_111
);
}
11 changes: 11 additions & 0 deletions tests/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use assert_cmd::Command;
use assert_fs::TempDir;
use std::path::{Path, PathBuf};

/// A test environment that provides convenient methods for running juliaup and julia commands
/// with isolated depot directories.
Expand Down Expand Up @@ -33,4 +34,14 @@ impl TestEnv {
cmd.env("JULIAUP_DEPOT_PATH", self.depot_dir.path());
cmd
}

/// Get the path to the juliaup config file
pub fn config_path(&self) -> PathBuf {
self.depot_dir.path().join("juliaup").join("juliaup.json")
}

/// Get the depot directory path
pub fn depot_path(&self) -> &Path {
self.depot_dir.path()
}
}
Loading