use std::sync::Mutex; use pretty_assertions::assert_eq; use super::INSTALL_URL; use super::InstallerHttp; use super::InstallerResponse; use super::fetch_installer_script; use super::update_modes_for_identities; use crate::RestartMode; use crate::UpdaterRefreshMode; use crate::managed_install::executable_identity_from_bytes; #[test] fn unchanged_updater_uses_version_based_restart() { assert_eq!( update_modes_for_identities( &executable_identity_from_bytes(b"same"), &executable_identity_from_bytes(b"same"), ), (RestartMode::IfVersionChanged, UpdaterRefreshMode::None) ); } #[test] fn changed_updater_forces_refresh_even_when_version_may_match() { assert_eq!( update_modes_for_identities( &executable_identity_from_bytes(b"old"), &executable_identity_from_bytes(b"new"), ), ( RestartMode::Always, UpdaterRefreshMode::ReexecIfManagedBinaryChanged, ) ); } #[tokio::test] async fn installer_fetch_uses_exact_url_and_preserves_bytes() { let script = b"#!/bin/sh\nprintf 'update bytes'\n".to_vec(); let http = FakeInstallerHttp::new(InstallerResponse::Success(script.clone())); assert_eq!( fetch_installer_script(&http) .await .expect("installer fetch should succeed"), script ); assert_eq!(http.requested_urls(), vec![INSTALL_URL.to_string()]); } #[tokio::test] async fn installer_fetch_rejects_non_success_status() { let http = FakeInstallerHttp::new(InstallerResponse::Unsuccessful { status: 503 }); let error = fetch_installer_script(&http) .await .expect_err("non-success response should fail"); assert!(error.to_string().contains("503")); assert_eq!(http.requested_urls(), vec![INSTALL_URL.to_string()]); } struct FakeInstallerHttp { response: InstallerResponse, requested_urls: Mutex>, } impl FakeInstallerHttp { fn new(response: InstallerResponse) -> Self { Self { response, requested_urls: Mutex::new(Vec::new()), } } fn requested_urls(&self) -> Vec { self.requested_urls .lock() .unwrap_or_else(std::sync::PoisonError::into_inner) .clone() } } impl InstallerHttp for FakeInstallerHttp { async fn get(&self, url: &str) -> anyhow::Result { self.requested_urls .lock() .unwrap_or_else(std::sync::PoisonError::into_inner) .push(url.to_string()); Ok(self.response.clone()) } }