ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
266 lines
8.3 KiB
Rust
266 lines
8.3 KiB
Rust
#![cfg(unix)]
|
|
|
|
use sha2::{Digest, Sha256};
|
|
use std::fs;
|
|
use std::os::unix::fs::PermissionsExt;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
use tempfile::TempDir;
|
|
|
|
const VERSION: &str = "9.8.7-rc3";
|
|
|
|
fn write_executable(path: &Path, body: &str) {
|
|
fs::write(path, body).unwrap();
|
|
let mut permissions = fs::metadata(path).unwrap().permissions();
|
|
permissions.set_mode(0o755);
|
|
fs::set_permissions(path, permissions).unwrap();
|
|
}
|
|
|
|
struct InstallerFixture {
|
|
root: TempDir,
|
|
fake_bin: PathBuf,
|
|
archive: PathBuf,
|
|
checksum: PathBuf,
|
|
curl_log: PathBuf,
|
|
git_log: PathBuf,
|
|
version: String,
|
|
}
|
|
|
|
impl InstallerFixture {
|
|
fn new(version: &str) -> Self {
|
|
let root = tempfile::tempdir().unwrap();
|
|
let fake_bin = root.path().join("fake-bin");
|
|
let stage = root.path().join("stage/dosh");
|
|
fs::create_dir_all(fake_bin.as_path()).unwrap();
|
|
fs::create_dir_all(stage.join("bin")).unwrap();
|
|
fs::write(stage.join("VERSION"), format!("{version}\n")).unwrap();
|
|
write_executable(
|
|
&stage.join("bin/dosh-client"),
|
|
"#!/bin/sh\nprintf 'fixture dosh\\n'\n",
|
|
);
|
|
|
|
let archive = root.path().join("dosh-macos-aarch64.tar.gz");
|
|
let status = Command::new("tar")
|
|
.args(["-C", root.path().join("stage").to_str().unwrap(), "-czf"])
|
|
.arg(&archive)
|
|
.arg("dosh")
|
|
.status()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
let digest = Sha256::digest(fs::read(&archive).unwrap());
|
|
let checksum = root.path().join("dosh-macos-aarch64.tar.gz.sha256");
|
|
fs::write(
|
|
&checksum,
|
|
format!("{digest:x} dosh-macos-aarch64.tar.gz\n"),
|
|
)
|
|
.unwrap();
|
|
|
|
write_executable(
|
|
&fake_bin.join("uname"),
|
|
"#!/bin/sh\ncase \"${1:-}\" in -s) echo Darwin;; -m) echo arm64;; *) echo Darwin;; esac\n",
|
|
);
|
|
let curl_log = root.path().join("curl.log");
|
|
let git_log = root.path().join("git.log");
|
|
write_executable(
|
|
&fake_bin.join("curl"),
|
|
r#"#!/bin/sh
|
|
printf '%s\n' "$*" >>"$TEST_CURL_LOG"
|
|
out=
|
|
previous=
|
|
url=
|
|
for arg in "$@"; do
|
|
if [ "$previous" = "-o" ]; then out="$arg"; fi
|
|
previous="$arg"
|
|
case "$arg" in http://*|https://*) url="$arg";; esac
|
|
done
|
|
case "$url" in
|
|
*/raw/branch/main/Cargo.toml)
|
|
printf '[package]\nname = "dosh"\nversion = "%s"\n' "$TEST_RELEASE_VERSION"
|
|
;;
|
|
*.sha256)
|
|
cp "$TEST_ARCHIVE_CHECKSUM" "$out"
|
|
;;
|
|
*/releases/download/*)
|
|
[ "${TEST_FAIL_ARCHIVE:-0}" = 1 ] && exit 22
|
|
cp "$TEST_ARCHIVE" "$out"
|
|
;;
|
|
*) exit 22;;
|
|
esac
|
|
"#,
|
|
);
|
|
|
|
Self {
|
|
root,
|
|
fake_bin,
|
|
archive,
|
|
checksum,
|
|
curl_log,
|
|
git_log,
|
|
version: version.to_string(),
|
|
}
|
|
}
|
|
|
|
fn command(&self, cwd: &Path) -> Command {
|
|
let mut command = Command::new("sh");
|
|
command
|
|
.arg(format!("{}/install.sh", env!("CARGO_MANIFEST_DIR")))
|
|
.args([
|
|
"client",
|
|
"--repo",
|
|
"https://example.invalid/Palav/dosh.git",
|
|
"--prefix",
|
|
])
|
|
.arg(self.root.path().join("prefix"))
|
|
.current_dir(cwd)
|
|
.env("HOME", self.root.path().join("home"))
|
|
.env(
|
|
"PATH",
|
|
format!(
|
|
"{}:{}",
|
|
self.fake_bin.display(),
|
|
std::env::var("PATH").unwrap_or_default()
|
|
),
|
|
)
|
|
.env("DOSH_BINARY_REQUIRED", "1")
|
|
.env("TEST_RELEASE_VERSION", &self.version)
|
|
.env("TEST_ARCHIVE", &self.archive)
|
|
.env("TEST_ARCHIVE_CHECKSUM", &self.checksum)
|
|
.env("TEST_CURL_LOG", &self.curl_log)
|
|
.env("TEST_GIT_LOG", &self.git_log);
|
|
command
|
|
}
|
|
|
|
fn installed_client(&self) -> PathBuf {
|
|
self.root.path().join("prefix/bin/dosh-client")
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_uses_repository_version_even_inside_an_unrelated_rust_project() {
|
|
let fixture = InstallerFixture::new(VERSION);
|
|
let unrelated = fixture.root.path().join("unrelated");
|
|
fs::create_dir_all(&unrelated).unwrap();
|
|
fs::write(
|
|
unrelated.join("Cargo.toml"),
|
|
"[package]\nname = \"not-dosh\"\nversion = \"99.0.0\"\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let output = fixture.command(&unrelated).output().unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"installer failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
assert!(fixture.installed_client().is_file());
|
|
let requests = fs::read_to_string(&fixture.curl_log).unwrap();
|
|
assert!(requests.contains("/raw/branch/main/Cargo.toml"));
|
|
assert!(requests.contains(&format!(
|
|
"/releases/download/v{VERSION}/dosh-macos-aarch64.tar.gz"
|
|
)));
|
|
assert!(!requests.contains("/releases/latest"));
|
|
assert!(!requests.contains("99.0.0"));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_source_fallback_checks_out_the_same_release_tag() {
|
|
let fixture = InstallerFixture::new(VERSION);
|
|
write_executable(
|
|
&fixture.fake_bin.join("git"),
|
|
r#"#!/bin/sh
|
|
printf '%s\n' "$*" >>"$TEST_GIT_LOG"
|
|
if [ "${1:-}" = clone ]; then
|
|
for destination in "$@"; do :; done
|
|
mkdir -p "$destination/.git"
|
|
fi
|
|
"#,
|
|
);
|
|
write_executable(
|
|
&fixture.fake_bin.join("cargo"),
|
|
"#!/bin/sh\nmkdir -p target/release\nprintf '#!/bin/sh\\n' >target/release/dosh-client\nchmod +x target/release/dosh-client\n",
|
|
);
|
|
let cwd = fixture.root.path().join("plain");
|
|
fs::create_dir_all(&cwd).unwrap();
|
|
let mut command = fixture.command(&cwd);
|
|
command
|
|
.env("DOSH_BINARY_REQUIRED", "0")
|
|
.env("TEST_FAIL_ARCHIVE", "1");
|
|
|
|
let output = command.output().unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"installer failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
assert!(fixture.installed_client().is_file());
|
|
let git = fs::read_to_string(&fixture.git_log).unwrap();
|
|
assert!(git.contains(&format!("clone --depth 1 --branch v{VERSION}")));
|
|
assert!(!git.contains("--branch main"));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_resolves_a_stable_repository_version_without_latest_redirects() {
|
|
let version = "1.2.3";
|
|
let fixture = InstallerFixture::new(version);
|
|
let cwd = fixture.root.path().join("plain");
|
|
fs::create_dir_all(&cwd).unwrap();
|
|
|
|
let output = fixture.command(&cwd).output().unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"installer failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
let requests = fs::read_to_string(&fixture.curl_log).unwrap();
|
|
assert!(requests.contains(&format!(
|
|
"/releases/download/v{version}/dosh-macos-aarch64.tar.gz"
|
|
)));
|
|
assert!(!requests.contains("/releases/latest"));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_repairs_a_legacy_updater_that_requests_its_old_tag() {
|
|
let fixture = InstallerFixture::new(VERSION);
|
|
let cwd = fixture.root.path().join("plain");
|
|
fs::create_dir_all(&cwd).unwrap();
|
|
let mut command = fixture.command(&cwd);
|
|
command.env("DOSH_BINARY_VERSION", "v0.1.17");
|
|
|
|
let output = command.output().unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"installer failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
let requests = fs::read_to_string(&fixture.curl_log).unwrap();
|
|
assert!(requests.contains(&format!(
|
|
"/releases/download/v{VERSION}/dosh-macos-aarch64.tar.gz"
|
|
)));
|
|
assert!(!requests.contains("/releases/download/v0.1.17/"));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_honors_an_explicit_exact_release_pin() {
|
|
let pinned = "0.1.17";
|
|
let fixture = InstallerFixture::new(pinned);
|
|
let cwd = fixture.root.path().join("plain");
|
|
fs::create_dir_all(&cwd).unwrap();
|
|
let mut command = fixture.command(&cwd);
|
|
command
|
|
.env("TEST_RELEASE_VERSION", VERSION)
|
|
.env("DOSH_BINARY_VERSION", format!("v{pinned}"))
|
|
.env("DOSH_BINARY_EXACT", "1");
|
|
|
|
let output = command.output().unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"installer failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
let requests = fs::read_to_string(&fixture.curl_log).unwrap();
|
|
assert!(requests.contains(&format!(
|
|
"/releases/download/v{pinned}/dosh-macos-aarch64.tar.gz"
|
|
)));
|
|
assert!(!requests.contains(&format!("/releases/download/v{VERSION}/")));
|
|
}
|