summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-11-08 13:23:18 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-11-08 13:23:18 +0100
commite914beb13e7099162ece01cd534bd7e4c89e91d5 (patch)
treea2b784833c207bae627623c99ac4c2a9ca2cbdaf
parent3de3c630c6f6884fea454b54f3cc81457d142db4 (diff)
parente2d67b8b81115a28074dd1eaa60d88666becf305 (diff)
downloadmullvadvpn-e914beb13e7099162ece01cd534bd7e4c89e91d5.tar.xz
mullvadvpn-e914beb13e7099162ece01cd534bd7e4c89e91d5.zip
Merge branch 'prevent-apt-and-dnf-from-being-confused-about-package-des-1412'
-rw-r--r--mullvad-version/src/lib.rs61
-rw-r--r--mullvad-version/src/main.rs38
-rw-r--r--test/Cargo.lock10
-rw-r--r--test/Cargo.toml1
-rw-r--r--test/test-manager/Cargo.toml2
-rw-r--r--test/test-manager/src/tests/config.rs12
-rw-r--r--test/test-manager/src/tests/install.rs14
-rw-r--r--test/test-rpc/src/client.rs10
-rw-r--r--test/test-rpc/src/lib.rs3
-rw-r--r--test/test-runner/Cargo.toml1
-rw-r--r--test/test-runner/src/app.rs19
-rw-r--r--test/test-runner/src/main.rs5
-rw-r--r--test/test-runner/src/net.rs4
-rw-r--r--test/test-runner/src/package.rs7
14 files changed, 143 insertions, 44 deletions
diff --git a/mullvad-version/src/lib.rs b/mullvad-version/src/lib.rs
index 9586b9b776..71cb27e55d 100644
--- a/mullvad-version/src/lib.rs
+++ b/mullvad-version/src/lib.rs
@@ -1,2 +1,63 @@
+use std::fmt::Display;
+use std::str::FromStr;
+use std::sync::LazyLock;
+
+use regex::Regex;
+
/// The Mullvad VPN app product version
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/product-version.txt"));
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct Version {
+ pub year: String,
+ pub incremental: String,
+ pub beta: Option<String>,
+}
+
+impl Version {
+ pub fn parse(version: &str) -> Version {
+ Version::from_str(version).unwrap()
+ }
+}
+
+impl Display for Version {
+ /// Format Version as a string: year.incremental{-beta}
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let Version {
+ year,
+ incremental,
+ beta,
+ } = &self;
+ match beta {
+ Some(beta) => write!(f, "{year}.{incremental}-{beta}"),
+ None => write!(f, "{year}.{incremental}"),
+ }
+ }
+}
+
+impl FromStr for Version {
+ type Err = String;
+
+ fn from_str(version: &str) -> Result<Self, Self::Err> {
+ const VERSION_REGEX: &str =
+ r"^20([0-9]{2})\.([1-9][0-9]?)(-beta([1-9][0-9]?))?(-dev-[0-9a-f]+)?$";
+ static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(VERSION_REGEX).unwrap());
+
+ let captures = RE
+ .captures(version)
+ .ok_or_else(|| format!("Version does not match expected format: {version}"))?;
+ let year = captures.get(1).expect("Missing year").as_str().to_owned();
+ let incremental = captures
+ .get(2)
+ .ok_or("Missing incremental")?
+ .as_str()
+ .to_owned();
+ let beta = captures.get(4).map(|m| m.as_str().to_owned());
+
+ Ok(Version {
+ year,
+ incremental,
+ beta,
+ })
+ }
+}
diff --git a/mullvad-version/src/main.rs b/mullvad-version/src/main.rs
index a4892633c9..ef72286eb7 100644
--- a/mullvad-version/src/main.rs
+++ b/mullvad-version/src/main.rs
@@ -1,13 +1,9 @@
-use regex::Regex;
+use mullvad_version::Version;
use std::{env, process::exit};
const ANDROID_VERSION: &str =
include_str!(concat!(env!("OUT_DIR"), "/android-product-version.txt"));
-const VERSION_REGEX: &str = r"^20([0-9]{2})\.([1-9][0-9]?)(-beta([1-9][0-9]?))?(-dev-[0-9a-f]+)?$";
-
-const ANDROID_STABLE_VERSION_CODE_SUFFIX: &str = "99";
-
fn main() {
let command = env::args().nth(1);
match command.as_deref() {
@@ -53,7 +49,9 @@ fn to_semver(version: &str) -> String {
/// Version: 2021.34
/// versionCode: 21340099
fn to_android_version_code(version: &str) -> String {
- let version = parse_version(version);
+ const ANDROID_STABLE_VERSION_CODE_SUFFIX: &str = "99";
+
+ let version = Version::parse(version);
format!(
"{}{:0>2}00{:0>2}",
version.year,
@@ -67,7 +65,7 @@ fn to_android_version_code(version: &str) -> String {
fn to_windows_h_format(version: &str) -> String {
let Version {
year, incremental, ..
- } = parse_version(version);
+ } = Version::parse(version);
format!(
"#define MAJOR_VERSION 20{year}
@@ -76,29 +74,3 @@ fn to_windows_h_format(version: &str) -> String {
#define PRODUCT_VERSION \"{version}\""
)
}
-
-struct Version {
- year: String,
- incremental: String,
- beta: Option<String>,
-}
-
-fn parse_version(version: &str) -> Version {
- let re = Regex::new(VERSION_REGEX).unwrap();
- let captures = re
- .captures(version)
- .expect("Version does not match expected format");
- let year = captures.get(1).expect("Missing year").as_str().to_owned();
- let incremental = captures
- .get(2)
- .expect("Missing incremental")
- .as_str()
- .to_owned();
- let beta = captures.get(4).map(|m| m.as_str().to_owned());
-
- Version {
- year,
- incremental,
- beta,
- }
-}
diff --git a/test/Cargo.lock b/test/Cargo.lock
index dcbe9aef95..24852c3356 100644
--- a/test/Cargo.lock
+++ b/test/Cargo.lock
@@ -1998,6 +1998,13 @@ dependencies = [
]
[[package]]
+name = "mullvad-version"
+version = "0.0.0"
+dependencies = [
+ "regex",
+]
+
+[[package]]
name = "multimap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3444,8 +3451,8 @@ dependencies = [
"mullvad-management-interface",
"mullvad-relay-selector",
"mullvad-types",
+ "mullvad-version",
"nix 0.29.0",
- "once_cell",
"pcap",
"pnet_base",
"pnet_packet",
@@ -3507,7 +3514,6 @@ dependencies = [
"log",
"mullvad-paths",
"nix 0.29.0",
- "once_cell",
"parity-tokio-ipc",
"plist",
"rand 0.8.5",
diff --git a/test/Cargo.toml b/test/Cargo.toml
index 8c691719ec..6215916992 100644
--- a/test/Cargo.toml
+++ b/test/Cargo.toml
@@ -75,7 +75,6 @@ shadowsocks-service = "1.20.3"
windows-sys = "0.52.0"
chrono = { version = "0.4.26", default-features = false }
clap = { version = "4.2.7", features = ["cargo", "derive"] }
-once_cell = "1.16.0"
bytes = "1.3.0"
async-trait = "0.1.58"
surge-ping = "0.8"
diff --git a/test/test-manager/Cargo.toml b/test/test-manager/Cargo.toml
index 80c8170635..2671ea454a 100644
--- a/test/test-manager/Cargo.toml
+++ b/test/test-manager/Cargo.toml
@@ -22,7 +22,6 @@ thiserror = { workspace = true }
bytes = { workspace = true }
test_macro = { path = "./test_macro" }
ipnetwork = "0.20"
-once_cell = { workspace = true }
inventory = "0.3"
data-encoding-macro = "0.1.12"
itertools = "0.10.5"
@@ -57,6 +56,7 @@ mullvad-api = { path = "../../mullvad-api", features = ["api-override"] }
mullvad-management-interface = { path = "../../mullvad-management-interface" }
mullvad-relay-selector = { path = "../../mullvad-relay-selector" }
mullvad-types = { path = "../../mullvad-types" }
+mullvad-version = { path = "../../mullvad-version" }
talpid-types = { path = "../../talpid-types" }
ssh2 = "0.9.4"
diff --git a/test/test-manager/src/tests/config.rs b/test/test-manager/src/tests/config.rs
index ae2f434698..04b2e01e71 100644
--- a/test/test-manager/src/tests/config.rs
+++ b/test/test-manager/src/tests/config.rs
@@ -1,7 +1,9 @@
-use once_cell::sync::OnceCell;
+use std::sync::OnceLock;
use std::{ops::Deref, path::Path};
use test_rpc::meta::Os;
+pub static TEST_CONFIG: TestConfigContainer = TestConfigContainer::new();
+
/// Default `mullvad_host`. This should match the production env.
pub const DEFAULT_MULLVAD_HOST: &str = "mullvad.net";
/// Bundled OpenVPN CA certificate use with the installed Mullvad app.
@@ -110,9 +112,13 @@ impl Default for BootstrapScript {
}
#[derive(Debug, Clone)]
-pub struct TestConfigContainer(OnceCell<TestConfig>);
+pub struct TestConfigContainer(OnceLock<TestConfig>);
impl TestConfigContainer {
+ const fn new() -> Self {
+ TestConfigContainer(OnceLock::new())
+ }
+
/// Initializes the constants.
///
/// # Panics
@@ -130,5 +136,3 @@ impl Deref for TestConfigContainer {
self.0.get().unwrap()
}
}
-
-pub static TEST_CONFIG: TestConfigContainer = TestConfigContainer(OnceCell::new());
diff --git a/test/test-manager/src/tests/install.rs b/test/test-manager/src/tests/install.rs
index 2f787f6299..ee4062ae89 100644
--- a/test/test-manager/src/tests/install.rs
+++ b/test/test-manager/src/tests/install.rs
@@ -107,6 +107,20 @@ pub async fn test_upgrade_app(
if rpc.mullvad_daemon_get_status().await? != ServiceStatus::Running {
bail!(Error::DaemonNotRunning);
}
+
+ // Verify that the correct version was installed
+ let running_daemon_version = rpc.mullvad_daemon_version().await?;
+ let running_daemon_version =
+ mullvad_version::Version::parse(&running_daemon_version).to_string();
+ ensure!(
+ &TEST_CONFIG
+ .app_package_filename
+ .contains(&running_daemon_version),
+ "Incorrect deamon version installed. Expected {expected} but {actual} is installed",
+ expected = TEST_CONFIG.app_package_filename.clone(),
+ actual = running_daemon_version
+ );
+
// Check if any traffic was observed
//
let guest_ip = pinger.guest_ip;
diff --git a/test/test-rpc/src/client.rs b/test/test-rpc/src/client.rs
index da64dc4658..e1a8bc5ef9 100644
--- a/test/test-rpc/src/client.rs
+++ b/test/test-rpc/src/client.rs
@@ -141,6 +141,16 @@ impl ServiceClient {
.map_err(Error::Tarpc)
}
+ /// Return the version string as reported by `mullvad --version`.
+ ///
+ /// TODO: Replace with nicer version type.
+ pub async fn mullvad_daemon_version(&self) -> Result<String, Error> {
+ self.client
+ .mullvad_version(tarpc::context::current())
+ .await
+ .map_err(Error::Tarpc)?
+ }
+
/// Returns all Mullvad app files, directories, and other data found on the system.
pub async fn find_mullvad_app_traces(&self) -> Result<Vec<AppTrace>, Error> {
self.client
diff --git a/test/test-rpc/src/lib.rs b/test/test-rpc/src/lib.rs
index 1ec8fb7321..7c10f0df53 100644
--- a/test/test-rpc/src/lib.rs
+++ b/test/test-rpc/src/lib.rs
@@ -156,6 +156,9 @@ mod service {
/// Return status of the system service.
async fn mullvad_daemon_get_status() -> mullvad_daemon::ServiceStatus;
+ /// Return version number of installed daemon.
+ async fn mullvad_version() -> Result<String, Error>;
+
/// Returns all Mullvad app files, directories, and other data found on the system.
async fn find_mullvad_app_traces() -> Result<Vec<AppTrace>, Error>;
diff --git a/test/test-runner/Cargo.toml b/test/test-runner/Cargo.toml
index 8df61e7164..fd53f4b7cb 100644
--- a/test/test-runner/Cargo.toml
+++ b/test/test-runner/Cargo.toml
@@ -18,7 +18,6 @@ tokio = { workspace = true }
tokio-serial = { workspace = true }
thiserror = { workspace = true }
log = { workspace = true }
-once_cell = { workspace = true }
parity-tokio-ipc = "0.9"
bytes = { workspace = true }
serde = { workspace = true }
diff --git a/test/test-runner/src/app.rs b/test/test-runner/src/app.rs
index f4e1fc3c53..6c6ed0b369 100644
--- a/test/test-runner/src/app.rs
+++ b/test/test-runner/src/app.rs
@@ -3,6 +3,25 @@ use std::path::{Path, PathBuf};
use test_rpc::{AppTrace, Error};
+/// Get the installed app version string
+pub async fn version() -> Result<String, Error> {
+ let version = tokio::process::Command::new("mullvad")
+ .arg("--version")
+ .output()
+ .await
+ .map_err(|e| Error::Service(e.to_string()))?;
+ let version = String::from_utf8(version.stdout).map_err(|err| Error::Other(err.to_string()))?;
+ // HACK: The output from `mullvad --version` includes the `mullvad-cli` binary name followed by
+ // the version string. Simply remove the leading noise and get at the version string.
+ let Some(version) = version.split_whitespace().nth(1) else {
+ return Err(Error::Other(
+ "Could not parse version number from `mullvad-cli --version`".to_string(),
+ ));
+ };
+ let version = version.to_string();
+ Ok(version)
+}
+
#[cfg(target_os = "windows")]
pub fn find_traces() -> Result<Vec<AppTrace>, Error> {
// TODO: Check GUI data
diff --git a/test/test-runner/src/main.rs b/test/test-runner/src/main.rs
index 735e61360e..a107f29f3c 100644
--- a/test/test-runner/src/main.rs
+++ b/test/test-runner/src/main.rs
@@ -136,6 +136,11 @@ impl Service for TestServer {
get_pipe_status()
}
+ /// Get the installed app version
+ async fn mullvad_version(self, _: context::Context) -> Result<String, test_rpc::Error> {
+ app::version().await
+ }
+
async fn find_mullvad_app_traces(
self,
_: context::Context,
diff --git a/test/test-runner/src/net.rs b/test/test-runner/src/net.rs
index a12fa2776c..7d32f04812 100644
--- a/test/test-runner/src/net.rs
+++ b/test/test-runner/src/net.rs
@@ -251,10 +251,10 @@ pub fn get_interface_mac(_interface: &str) -> Result<Option<[u8; 6]>, test_rpc::
#[cfg(target_os = "windows")]
pub fn get_default_interface() -> &'static str {
- use once_cell::sync::OnceCell;
+ use std::sync::OnceLock;
use talpid_platform_metadata::WindowsVersion;
- static WINDOWS_VERSION: OnceCell<WindowsVersion> = OnceCell::new();
+ static WINDOWS_VERSION: OnceLock<WindowsVersion> = OnceLock::new();
let version = WINDOWS_VERSION
.get_or_init(|| WindowsVersion::new().expect("failed to obtain Windows version"));
diff --git a/test/test-runner/src/package.rs b/test/test-runner/src/package.rs
index 8de1f32c3f..5cc0b92dab 100644
--- a/test/test-runner/src/package.rs
+++ b/test/test-runner/src/package.rs
@@ -173,6 +173,13 @@ fn apt_command() -> Command {
// instead.
cmd.args(["-o", "DPkg::Lock::Timeout=60"]);
cmd.arg("-qy");
+ // `apt` may consider installing a development build to be a downgrade from the baseline if the
+ // major version is identical, in which case the ordering is incorrectly based on the git hash
+ // suffix.
+ //
+ // Note that this is only sound if we take precaution to check the installed version after
+ // running this command.
+ cmd.arg("--allow-downgrades");
cmd.env("DEBIAN_FRONTEND", "noninteractive");