Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Whitelist relays in an end to end test framwork config #7454

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
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 mullvad-api/src/availability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl ApiAvailability {
/// starting it if it's not currently running.
pub fn reset_inactivity_timer(&self) {
let mut inner = self.acquire();
log::debug!("Restarting API inactivity check");
log::trace!("Restarting API inactivity check");
inner.stop_inactivity_timer();
let availability_handle = self.clone();
inner.inactivity_timer = Some(tokio::spawn(async move {
Expand Down Expand Up @@ -252,7 +252,7 @@ impl ApiAvailabilityState {
}

fn stop_inactivity_timer(&mut self) {
log::debug!("Stopping API inactivity check");
log::trace!("Stopping API inactivity check");
if let Some(timer) = self.inactivity_timer.take() {
timer.abort();
}
Expand Down
2 changes: 1 addition & 1 deletion mullvad-cli/src/cmds/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ pub async fn resolve_location_constraint(
} else {
// The Constraint was not a relay, assuming it to be a location
let location_constraint: Constraint<GeographicLocationConstraint> =
Constraint::from(location_constraint_args);
Constraint::try_from(location_constraint_args)?;

// If the location constraint was not "any", then validate the country/city
if let Constraint::Only(constraint) = &location_constraint {
Expand Down
61 changes: 37 additions & 24 deletions mullvad-cli/src/cmds/relay_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,51 @@ pub struct LocationArgs {
pub hostname: Option<Hostname>,
}

impl From<LocationArgs> for Constraint<GeographicLocationConstraint> {
fn from(value: LocationArgs) -> Self {
if value.country.eq_ignore_ascii_case("any") {
return Constraint::Any;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Failed to parse location constraint from input: TODO")]
Parse,
}

impl TryFrom<LocationArgs> for GeographicLocationConstraint {
type Error = Error;

fn try_from(value: LocationArgs) -> Result<Self, Self::Error> {
match (value.country, value.city, value.hostname) {
(country, None, None) => Ok(GeographicLocationConstraint::Country(country)),
(country, Some(city), None) => Ok(GeographicLocationConstraint::City(country, city)),
(country, Some(city), Some(hostname)) => Ok(GeographicLocationConstraint::Hostname(
country, city, hostname,
)),
_ => Err(Error::Parse),
//_ => unreachable!("invalid location arguments"),
}
}
}

Constraint::Only(match (value.country, value.city, value.hostname) {
(country, None, None) => GeographicLocationConstraint::Country(country),
(country, Some(city), None) => GeographicLocationConstraint::City(country, city),
(country, Some(city), Some(hostname)) => {
GeographicLocationConstraint::Hostname(country, city, hostname)
}
impl TryFrom<LocationArgs> for LocationConstraint {
type Error = Error;

_ => unreachable!("invalid location arguments"),
})
fn try_from(value: LocationArgs) -> Result<Self, Self::Error> {
GeographicLocationConstraint::try_from(value).map(LocationConstraint::from)
}
}

impl From<LocationArgs> for Constraint<LocationConstraint> {
fn from(value: LocationArgs) -> Self {
impl TryFrom<LocationArgs> for Constraint<GeographicLocationConstraint> {
type Error = Error;

fn try_from(value: LocationArgs) -> Result<Self, Self::Error> {
if value.country.eq_ignore_ascii_case("any") {
return Constraint::Any;
return Ok(Constraint::Any);
}
GeographicLocationConstraint::try_from(value).map(Constraint::Only)
}
}

impl TryFrom<LocationArgs> for Constraint<LocationConstraint> {
type Error = Error;

let location = match (value.country, value.city, value.hostname) {
(country, None, None) => GeographicLocationConstraint::Country(country),
(country, Some(city), None) => GeographicLocationConstraint::City(country, city),
(country, Some(city), Some(hostname)) => {
GeographicLocationConstraint::Hostname(country, city, hostname)
}
_ => unreachable!("invalid location arguments"),
};
Constraint::Only(LocationConstraint::Location(location))
fn try_from(value: LocationArgs) -> Result<Self, Self::Error> {
LocationConstraint::try_from(value).map(Constraint::Only)
}
}
53 changes: 53 additions & 0 deletions mullvad-types/src/relay_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ pub enum GeographicLocationConstraint {
Hostname(CountryCode, CityCode, Hostname),
}

#[derive(thiserror::Error, Debug)]
#[error("Failed to parse {input} into a geographic location constraint")]
pub struct ParseGeoLocationError {
input: String,
}

impl GeographicLocationConstraint {
/// Create a new [`GeographicLocationConstraint`] given a country.
pub fn country(country: impl Into<String>) -> Self {
Expand Down Expand Up @@ -227,6 +233,27 @@ impl Match<Relay> for GeographicLocationConstraint {
}
}

impl FromStr for GeographicLocationConstraint {
type Err = ParseGeoLocationError;

// TODO: Implement for country and city as well?
fn from_str(input: &str) -> Result<Self, Self::Err> {
// A host name, such as "se-got-wg-101" maps to
// Country: se
// City: got
// hostname: se-got-wg-101
let x = input.split("-").collect::<Vec<_>>();
match x[..] {
[country] => Ok(GeographicLocationConstraint::country(country)),
[country, city] => Ok(GeographicLocationConstraint::city(country, city)),
[country, city, ..] => Ok(GeographicLocationConstraint::hostname(country, city, input)),
_ => Err(ParseGeoLocationError {
input: input.to_string(),
}),
}
}
}

/// Limits the set of servers to choose based on ownership.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
Expand Down Expand Up @@ -677,3 +704,29 @@ impl RelayOverride {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse_hostname() {
// Parse a country
assert_eq!(
"se".parse::<GeographicLocationConstraint>().unwrap(),
GeographicLocationConstraint::country("se")
);
// Parse a city
assert_eq!(
"se-got".parse::<GeographicLocationConstraint>().unwrap(),
GeographicLocationConstraint::city("se", "got")
);
// Parse a hostname
assert_eq!(
"se-got-wg-101"
.parse::<GeographicLocationConstraint>()
.unwrap(),
GeographicLocationConstraint::hostname("se", "got", "se-got-wg-101")
);
}
}
1 change: 1 addition & 0 deletions test/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

136 changes: 68 additions & 68 deletions test/scripts/test-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ function get_test_utls_dir {
local script_path="${BASH_SOURCE[0]}"
local script_dir
if [[ -n "$script_path" ]]; then
script_dir="$(cd "$(dirname "$script_path")" > /dev/null && pwd)"
script_dir="$(cd "$(dirname "$script_path")" >/dev/null && pwd)"
else
script_dir="$(cd "$(dirname "$0")" > /dev/null && pwd)"
script_dir="$(cd "$(dirname "$0")" >/dev/null && pwd)"
fi
echo "$script_dir"
}
Expand Down Expand Up @@ -54,7 +54,7 @@ export CURRENT_VERSION
export LATEST_STABLE_RELEASE

function print_available_releases {
for release in $(jq -r '.[].tag_name'<<<"$RELEASES"); do
for release in $(jq -r '.[].tag_name' <<<"$RELEASES"); do
echo "$release"
done
}
Expand All @@ -73,7 +73,7 @@ function get_package_dir {
exit 1
fi

mkdir -p "$package_dir" || exit 1
mkdir -p "$package_dir" || exit 1
# Clean up old packages
find "$package_dir" -type f -mtime +5 -delete || true

Expand All @@ -89,7 +89,7 @@ function nice_time {
result=$?
fi
s=$SECONDS
echo "\"$*\" completed in $((s/60))m:$((s%60))s"
echo "\"$*\" completed in $((s / 60))m:$((s % 60))s"
return $result
}
# Matches $1 with a build version string and sets the following exported variables:
Expand Down Expand Up @@ -122,22 +122,22 @@ function get_app_filename {
version="${BUILD_VERSION}${COMMIT_HASH}${TAG:-}"
fi
case $os in
debian*|ubuntu*)
echo "MullvadVPN-${version}_amd64.deb"
;;
fedora*)
echo "MullvadVPN-${version}_x86_64.rpm"
;;
windows*)
echo "MullvadVPN-${version}.exe"
;;
macos*)
echo "MullvadVPN-${version}.pkg"
;;
*)
echo "Unsupported target: $os" 1>&2
return 1
;;
debian* | ubuntu*)
echo "MullvadVPN-${version}_amd64.deb"
;;
fedora*)
echo "MullvadVPN-${version}_x86_64.rpm"
;;
windows*)
echo "MullvadVPN-${version}.exe"
;;
macos*)
echo "MullvadVPN-${version}.pkg"
;;
*)
echo "Unsupported target: $os" 1>&2
return 1
;;
esac
}

Expand Down Expand Up @@ -177,19 +177,19 @@ function get_e2e_filename {
version="${BUILD_VERSION}${COMMIT_HASH}"
fi
case $os in
debian*|ubuntu*|fedora*)
echo "app-e2e-tests-${version}-x86_64-unknown-linux-gnu"
;;
windows*)
echo "app-e2e-tests-${version}-x86_64-pc-windows-msvc.exe"
;;
macos*)
echo "app-e2e-tests-${version}-aarch64-apple-darwin"
;;
*)
echo "Unsupported target: $os" 1>&2
return 1
;;
debian* | ubuntu* | fedora*)
echo "app-e2e-tests-${version}-x86_64-unknown-linux-gnu"
;;
windows*)
echo "app-e2e-tests-${version}-x86_64-pc-windows-msvc.exe"
;;
macos*)
echo "app-e2e-tests-${version}-aarch64-apple-darwin"
;;
*)
echo "Unsupported target: $os" 1>&2
return 1
;;
esac
}

Expand Down Expand Up @@ -282,38 +282,38 @@ function run_tests_for_os {
test_dir=$(get_test_utls_dir)/..
read -ra test_filters_arg <<<"${TEST_FILTERS:-}" # Split the string by words into an array
pushd "$test_dir"
if [ -n "${TEST_DIST_DIR+x}" ]; then
if [ ! -x "${TEST_DIST_DIR%/}/test-manager" ]; then
executable_not_found_in_dist_error test-manager
fi
test_manager="${TEST_DIST_DIR%/}/test-manager"
runner_dir_flag=("--runner-dir" "$TEST_DIST_DIR")
else
test_manager="cargo run --bin test-manager"
runner_dir_flag=()
if [ -n "${TEST_DIST_DIR+x}" ]; then
if [ ! -x "${TEST_DIST_DIR%/}/test-manager" ]; then
executable_not_found_in_dist_error test-manager
fi
test_manager="${TEST_DIST_DIR%/}/test-manager"
runner_dir_flag=("--runner-dir" "$TEST_DIST_DIR")
else
test_manager="cargo run --bin test-manager"
runner_dir_flag=()
fi

if [ -n "${MULLVAD_HOST+x}" ]; then
mullvad_host_arg=("--mullvad-host" "$MULLVAD_HOST")
else
mullvad_host_arg=()
fi
if [ -n "${MULLVAD_HOST+x}" ]; then
mullvad_host_arg=("--mullvad-host" "$MULLVAD_HOST")
else
mullvad_host_arg=()
fi

if ! RUST_LOG_STYLE=always $test_manager run-tests \
--account "${ACCOUNT_TOKEN:?Error: ACCOUNT_TOKEN not set}" \
--app-package "${APP_PACKAGE:?Error: APP_PACKAGE not set}" \
"${upgrade_package_arg[@]}" \
"${test_report_arg[@]}" \
--package-dir "${package_dir}" \
--vm "$vm" \
--openvpn-certificate "${OPENVPN_CERTIFICATE:-"assets/openvpn.ca.crt"}" \
"${mullvad_host_arg[@]}" \
"${test_filters_arg[@]}" \
"${runner_dir_flag[@]}" \
2>&1 | sed -r "s/${ACCOUNT_TOKEN}/\{ACCOUNT_TOKEN\}/g"; then
echo "Test run failed"
exit 1
fi
if ! RUST_LOG_STYLE=always $test_manager run-tests \
--account "${ACCOUNT_TOKEN:?Error: ACCOUNT_TOKEN not set}" \
--app-package "${APP_PACKAGE:?Error: APP_PACKAGE not set}" \
"${upgrade_package_arg[@]}" \
"${test_report_arg[@]}" \
--package-dir "${package_dir}" \
--vm "$vm" \
--openvpn-certificate "${OPENVPN_CERTIFICATE:-"assets/openvpn.ca.crt"}" \
"${mullvad_host_arg[@]}" \
"${test_filters_arg[@]}" \
"${runner_dir_flag[@]}" \
2>&1 | sed -r "s/${ACCOUNT_TOKEN}/\{ACCOUNT_TOKEN\}/g"; then
echo "Test run failed"
exit 1
fi
popd
}

Expand All @@ -335,10 +335,10 @@ function build_current_version {

if [ ! -f "$app_package" ]; then
pushd "$app_dir"
if [[ $(git diff --quiet) ]]; then
echo "WARNING: the app repository contains uncommitted changes, this script will only rebuild the app package when the git hash changes"
fi
./build.sh
if [[ $(git diff --quiet) ]]; then
echo "WARNING: the app repository contains uncommitted changes, this script will only rebuild the app package when the git hash changes"
fi
./build.sh
popd
echo "Moving '$(realpath "$app_dir/dist/$app_filename")' to '$(realpath "$app_package")'"
mv -n "$app_dir"/dist/"$app_filename" "$app_package"
Expand All @@ -348,7 +348,7 @@ function build_current_version {

if [ ! -f "$gui_test_bin" ]; then
pushd "$app_dir"/gui
npm run build-test-executable
npm run build-test-executable
popd
echo "Moving '$(realpath "$app_dir/dist/$gui_test_filename")' to '$(realpath "$gui_test_bin")'"
mv -n "$app_dir"/dist/"$gui_test_filename" "$gui_test_bin"
Expand Down
1 change: 1 addition & 0 deletions test/test-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ async-trait = { workspace = true }
uuid = "1.3"
dirs = "5.0.1"
scopeguard = "1.2"
glob = "0.3"

serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
Loading
Loading