Add rust command integration tests

This commit is contained in:
Caelan Sayler
2024-01-03 22:07:46 +00:00
parent d071ea92b4
commit 07fca1a5f5
13 changed files with 147 additions and 91 deletions

59
src/Rust/Cargo.lock generated
View File

@@ -91,9 +91,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca87830a3e3fb156dc96cfbd31cb620265dd053be734723f22b760d6cc3c3051"
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "as-slice"
@@ -234,7 +234,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -517,7 +517,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -999,7 +999,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -1087,18 +1087,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.72"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a293318316cf6478ec1ad2a21c49390a8d5b5eae9fab736467d93fbc0edc29c5"
checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -1191,7 +1191,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "remove_dir_all"
version = "0.8.2"
source = "git+https://github.com/caesay/remove_dir_all.git#f70d40ad7b6bb655a7a36268cd7cc5ea8e015c6d"
source = "git+https://github.com/caesay/remove_dir_all.git#c98142b9150c53e6c5f56e752d2bf93433f2e207"
dependencies = [
"cfg-if",
"cvt",
@@ -1277,28 +1277,28 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.20"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -1390,7 +1390,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -1406,9 +1406,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.43"
version = "2.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e"
dependencies = [
"proc-macro2",
"quote",
@@ -1439,22 +1439,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.53"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.53"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
]
[[package]]
@@ -1637,6 +1637,7 @@ dependencies = [
"simple-stopwatch",
"simplelog",
"strum",
"tempfile",
"ureq",
"wait-timeout",
"waitpid-any",
@@ -1717,7 +1718,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
"wasm-bindgen-shared",
]
@@ -1739,7 +1740,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.46",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2028,9 +2029,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.31"
version = "0.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
dependencies = [
"memchr",
]

View File

@@ -72,7 +72,6 @@ enum-flags = "0.3"
remove_dir_all = { git = "https://github.com/caesay/remove_dir_all.git", features = [
"log",
] }
ntest = "0.9.0"
zstd = "0.13"
sha1_smol = "1.0"
runas = "1.1"
@@ -131,6 +130,10 @@ windows-sys = { version = "0.52", default-features = false, features = [
normpath = "1.0.1"
codesign-verify = { git = "https://github.com/caesay/codesign-verify-rs.git" }
[dev-dependencies]
tempfile = "3.9"
ntest = "0.9.0"
[build-dependencies]
semver = "1.0"

View File

@@ -10,7 +10,7 @@ use std::{
};
use winsafe::{self as w, co};
pub fn install(debug_pkg: &Option<&PathBuf>, install_to: &Option<&PathBuf>) -> Result<()> {
pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Result<()> {
let osinfo = os_info::get();
info!("OS: {}, Arch={}", osinfo, osinfo.architecture().unwrap_or("unknown"));

View File

@@ -25,44 +25,3 @@ pub fn patch(old_file: &PathBuf, patch_file: &PathBuf, output_file: &PathBuf) ->
Ok(())
}
#[test]
fn test_patch_apply() {
fn find_fixtures() -> PathBuf {
let mut path = std::env::current_exe().unwrap();
while !path.join("Velopack.sln").exists() {
path.pop();
}
path.push("test");
path.push("fixtures");
path
}
let path = find_fixtures();
let old_file = path.join("obs29.1.2.dll");
let new_file = path.join("obs30.0.2.dll");
let p1 = path.join("obs-size.patch");
let p2 = path.join("obs-speed.patch");
fn get_sha1(file: &PathBuf) -> String {
let file_bytes = fs::read(file).unwrap();
let mut sha1 = sha1_smol::Sha1::new();
sha1.update(&file_bytes);
sha1.digest().to_string()
}
let expected_sha1 = get_sha1(&new_file);
let tmp_file = std::path::Path::new("temp.patch").to_path_buf();
patch(&old_file, &p1, &tmp_file).unwrap();
let tmp_sha1 = get_sha1(&tmp_file);
fs::remove_file(&tmp_file).unwrap();
assert_eq!(expected_sha1, tmp_sha1);
patch(&old_file, &p2, &tmp_file).unwrap();
let tmp_sha1 = get_sha1(&tmp_file);
fs::remove_file(&tmp_file).unwrap();
assert_eq!(expected_sha1, tmp_sha1);
}

View File

@@ -4,9 +4,8 @@ use anyhow::Result;
use std::fs::File;
use std::path::PathBuf;
pub fn uninstall() -> Result<()> {
pub fn uninstall(root_path: &PathBuf, app: &Manifest, delete_self: bool) -> Result<()> {
info!("Command: Uninstall");
let (root_path, app) = shared::detect_current_manifest()?;
fn _uninstall_impl(app: &Manifest, root_path: &PathBuf) -> bool {
// the real app could be running at the moment
@@ -23,7 +22,7 @@ pub fn uninstall() -> Result<()> {
}
info!("Removing directory '{}'", root_path.to_string_lossy());
if let Err(e) = shared::retry_io(|| remove_dir_all::remove_dir_containing_current_executable()) {
if let Err(e) = shared::retry_io(|| remove_dir_all::remove_dir_but_not_self(&root_path)) {
error!("Unable to remove directory, some files may be in use ({}).", e);
finished_with_errors = true;
}
@@ -50,8 +49,11 @@ pub fn uninstall() -> Result<()> {
let dead_path = root_path.join(".dead");
let _ = File::create(dead_path);
if let Err(e) = windows::register_intent_to_delete_self(3, &root_path) {
warn!("Unable to schedule self delete ({}).", e);
if delete_self {
if let Err(e) = windows::register_intent_to_delete_self(3, &root_path) {
warn!("Unable to schedule self delete ({}).", e);
}
}
Ok(())

View File

@@ -43,7 +43,7 @@ fn main() -> Result<()> {
info!(" Debug: {:?}", debug);
}
let res = commands::install(&debug, &installto);
let res = commands::install(debug, installto);
if let Err(e) = &res {
error!("An error has occurred: {}", e);
dialogs::show_error("Setup Error", None, format!("An error has occurred: {}", e).as_str());

View File

@@ -44,7 +44,7 @@ pub fn header_offset_and_length() -> (i64, i64) {
}
#[cfg(target_os = "windows")]
pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: &Option<&PathBuf>) -> Result<BundleInfo<'a>> {
pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: Option<&PathBuf>) -> Result<BundleInfo<'a>> {
info!("Reading bundle header...");
let (offset, length) = header_offset_and_length();
info!("Bundle offset = {}, length = {}", offset, length);
@@ -63,7 +63,7 @@ pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: &Option<&PathBuf>) -
if cfg!(debug_assertions) {
if let Some(pkg) = debug_pkg {
info!("Loading bundle from debug nupkg file...");
return load_bundle_from_file(pkg.to_owned());
return load_bundle_from_file(pkg);
}
}

View File

@@ -43,8 +43,8 @@ pub fn start_package<P: AsRef<Path>>(_app: &Manifest, root_dir: P, exe_args: Opt
Ok(())
}
pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
let mut manifest_path = std::env::current_exe()?;
pub fn detect_manifest_from_update_path(update_exe: &PathBuf) -> Result<(PathBuf, Manifest)> {
let mut manifest_path = update_exe.clone();
manifest_path.pop();
manifest_path.push("sq.version");
let manifest = load_manifest(&manifest_path)?;
@@ -64,6 +64,11 @@ pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
Ok((Path::new(&root_dir).to_path_buf(), manifest))
}
pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
let me = std::env::current_exe()?;
detect_manifest_from_update_path(&me)
}
fn load_manifest(nuspec_path: &PathBuf) -> Result<Manifest> {
if Path::new(&nuspec_path).exists() {
if let Ok(nuspec) = super::retry_io(|| std::fs::read_to_string(&nuspec_path)) {

View File

@@ -156,14 +156,8 @@ pub fn start_package<P: AsRef<Path>>(app: &Manifest, root_dir: P, exe_args: Opti
Ok(())
}
fn get_my_root_dir() -> Result<PathBuf> {
let mut my_dir = std::env::current_exe()?;
my_dir.pop();
Ok(my_dir)
}
pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
let root_path = get_my_root_dir()?;
pub fn detect_manifest_from_update_path(update_exe: &PathBuf) -> Result<(PathBuf, Manifest)> {
let root_path = update_exe.parent().unwrap().to_path_buf();
let app = find_manifest_from_root_dir(&root_path)
.map_err(|m| anyhow!("Unable to read application manifest ({}). Is this a properly installed application?", m))?;
info!("Loaded manifest for application: {}", app.id);
@@ -171,6 +165,11 @@ pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
Ok((root_path, app))
}
pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> {
let me = std::env::current_exe()?;
detect_manifest_from_update_path(&me)
}
fn find_manifest_from_root_dir(root_path: &PathBuf) -> Result<Manifest> {
// default to checking current/sq.version
let cm = find_current_manifest(root_path);

View File

@@ -160,7 +160,8 @@ fn start(matches: &ArgMatches) -> Result<()> {
#[cfg(target_os = "windows")]
fn uninstall(_matches: &ArgMatches) -> Result<()> {
info!("Command: Uninstall");
commands::uninstall()
let (root_path, app) = shared::detect_current_manifest()?;
commands::uninstall(&root_path, &app, true)
}
#[cfg(target_os = "windows")]

View File

@@ -0,0 +1,75 @@
mod common;
use common::*;
use std::{fs, path::Path, path::PathBuf};
use tempfile::tempdir;
use velopack::*;
#[cfg(target_os = "windows")]
use winsafe::{self as w, co};
#[cfg(target_os = "windows")]
#[test]
pub fn test_install_uninstall() {
logging::trace_logger();
dialogs::set_silent(true);
let fixtures = find_fixtures();
let app_id = "AvaloniaCrossPlat";
let pkg_name = "AvaloniaCrossPlat-1.0.11-win-full.nupkg";
let startmenu = w::SHGetKnownFolderPath(&co::KNOWNFOLDERID::StartMenu, co::KF::DONT_UNEXPAND, None).unwrap();
let lnk_path = Path::new(&startmenu).join("Programs").join(format!("{}.lnk", app_id));
if lnk_path.exists() {
fs::remove_file(&lnk_path).unwrap();
}
let nupkg = fixtures.join(pkg_name);
let tmp_dir = tempdir().unwrap();
let tmp_buf = tmp_dir.path().to_path_buf();
commands::install(Some(&nupkg), Some(&tmp_buf)).unwrap();
assert!(lnk_path.exists());
assert!(tmp_buf.join("Update.exe").exists());
assert!(tmp_buf.join("current").join("AvaloniaCrossPlat.exe").exists());
assert!(tmp_buf.join("current").join("sq.version").exists());
let (root_dir, app) = shared::detect_manifest_from_update_path(&tmp_buf.join("Update.exe")).unwrap();
assert_eq!(app_id, app.id);
commands::uninstall(&root_dir, &app, false).unwrap();
assert!(!tmp_buf.join("current").exists());
assert!(tmp_buf.join(".dead").exists());
assert!(!lnk_path.exists());
}
#[test]
pub fn test_patch_apply() {
dialogs::set_silent(true);
let fixtures = find_fixtures();
let old_file = fixtures.join("obs29.1.2.dll");
let new_file = fixtures.join("obs30.0.2.dll");
let p1 = fixtures.join("obs-size.patch");
let p2 = fixtures.join("obs-speed.patch");
fn get_sha1(file: &PathBuf) -> String {
let file_bytes = fs::read(file).unwrap();
let mut sha1 = sha1_smol::Sha1::new();
sha1.update(&file_bytes);
sha1.digest().to_string()
}
let expected_sha1 = get_sha1(&new_file);
let tmp_file = std::path::Path::new("temp.patch").to_path_buf();
commands::patch(&old_file, &p1, &tmp_file).unwrap();
let tmp_sha1 = get_sha1(&tmp_file);
fs::remove_file(&tmp_file).unwrap();
assert_eq!(expected_sha1, tmp_sha1);
commands::patch(&old_file, &p2, &tmp_file).unwrap();
let tmp_sha1 = get_sha1(&tmp_file);
fs::remove_file(&tmp_file).unwrap();
assert_eq!(expected_sha1, tmp_sha1);
}

View File

@@ -0,0 +1,11 @@
use std::path::PathBuf;
pub fn find_fixtures() -> PathBuf {
let mut path = std::env::current_exe().unwrap();
while !path.join("Velopack.sln").exists() {
path.pop();
}
path.push("test");
path.push("fixtures");
path
}

Binary file not shown.