From 5589c5f745fd5f2f98fa6029d9259295a9f93a2b Mon Sep 17 00:00:00 2001 From: czarte Date: Wed, 23 Apr 2025 19:00:16 +0200 Subject: [PATCH 1/5] make_node_record_cc and adjusting tests, get rid of free world bit --- node/src/neighborhood/mod.rs | 53 ++++++--------- .../src/neighborhood/neighborhood_database.rs | 2 - node/src/neighborhood/node_location.rs | 3 - node/src/neighborhood/node_record.rs | 9 --- .../src/test_utils/neighborhood_test_utils.rs | 65 ++++++------------- 5 files changed, 41 insertions(+), 91 deletions(-) diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index 448b0ffab..83ac28f2f 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -1232,10 +1232,6 @@ impl Neighborhood { } else { if let Some(node_record) = self.neighborhood_database.node_by_key(last_node_key) { if let Some(country_code) = &node_record.inner.country_code_opt { - println!("contains_country_code {}", self - .user_exit_preferences - .exit_countries - .contains(country_code)); return self .user_exit_preferences .exit_countries @@ -2210,12 +2206,7 @@ mod tests { use crate::test_utils::assert_contains; use crate::test_utils::make_meaningless_route; use crate::test_utils::make_wallet; - use crate::test_utils::neighborhood_test_utils::{ - cryptdes_from_node_records, db_from_node, linearly_connect_nodes, - make_global_cryptde_node_record, make_ip, make_node, make_node_descriptor, - make_node_record, make_node_record_f, make_node_records, neighborhood_from_nodes, - MIN_HOPS_FOR_TEST, - }; + use crate::test_utils::neighborhood_test_utils::{cryptdes_from_node_records, db_from_node, linearly_connect_nodes, make_global_cryptde_node_record, make_ip, make_node, make_node_descriptor, make_node_record, make_node_record_cc, make_node_record_f, make_node_records, neighborhood_from_nodes, MIN_HOPS_FOR_TEST}; use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock; use crate::test_utils::rate_pack; use crate::test_utils::recorder::make_recorder; @@ -2345,8 +2336,8 @@ mod tests { fn standard_gossip_results_in_exit_node_in_database() { let mut subject = make_standard_subject(); let root_node_key = subject.neighborhood_database.root_key().clone(); - let source_node = make_node_record(1111, true); //US - let first_node = make_node_record(2222, true); //FR + let source_node = make_node_record_cc(1111, true, "US"); + let first_node = make_node_record_cc(2222, true, "FR"); let second_node = make_node_record(3333, false); subject .neighborhood_database @@ -2400,8 +2391,8 @@ mod tests { PersistentConfigurationMock::new().set_past_neighbors_result(Ok(())); debut_subject.persistent_config_opt = Some(Box::new(persistent_config)); let debut_root_key = debut_subject.neighborhood_database.root_key().clone(); - let introducer_node = make_node_record(3333, true); //AU - let introducee = make_node_record(2222, true); //FR + let introducer_node = make_node_record_cc(3333, true, "AU"); //AU + let introducee = make_node_record_cc(2222, true, "FR"); //FR let introducer_root_key = introducer_node.public_key().clone(); let mut introducer_db = debut_subject.neighborhood_database.clone(); introducer_db.set_root_key(&introducer_root_key); @@ -3633,10 +3624,10 @@ mod tests { fn min_hops_change_affects_db_countries_and_exit_location_settings() { let mut subject = make_standard_subject(); let root_node_ch = subject.neighborhood_database.root().clone(); - let neighbor_one_au = make_node_record(1234, true); - let neighbor_two_fr = make_node_record(2345, true); - let neighbor_three_cn = make_node_record(3456, true); - let neighbor_four_us = make_node_record(4567, true); + let neighbor_one_au = make_node_record_cc(1234, true, "AU"); + let neighbor_two_fr = make_node_record_cc(2345, true, "FR"); + let neighbor_three_cn = make_node_record_cc(3456, true, "CN"); + let neighbor_four_us = make_node_record_cc(4567, true, "US"); subject .neighborhood_database .add_node(neighbor_one_au.clone()) @@ -4137,12 +4128,10 @@ mod tests { let system = System::new(test_name); let (ui_gateway, _, ui_gateway_recording_arc) = make_recorder(); subject.logger = Logger::new(test_name); - let cz = &mut make_node_record(3456, true); - cz.inner.country_code_opt = Some("CZ".to_string()); + let cz = &make_node_record_cc(3456, true, "CZ"); let standard_node_1 = &make_node_record(4567, true); - let fr = &mut make_node_record(5678, true); - fr.inner.country_code_opt = Some("FR".to_string()); - let standard_node_2 = &make_node_record(7777, true); + let fr = &make_node_record_cc(5678, true, "FR"); + let standard_node_2 = &make_node_record_cc(7777, true, "US"); let root_node = subject.neighborhood_database.root().clone(); let db = &mut subject.neighborhood_database; db.add_node(cz.clone()).unwrap(); @@ -4778,10 +4767,10 @@ mod tests { .root_mut() .public_key() .clone(); - let mut a_fr_node = make_node_record(2345, true); + let mut a_fr_node = make_node_record_cc(2345, true, "FR"); a_fr_node.inner.rate_pack.exit_byte_rate = 1; a_fr_node.inner.rate_pack.exit_service_rate = 1; - let mut c_au_node = make_node_record(1234, true); + let mut c_au_node = make_node_record_cc(1234, true, "AU"); c_au_node.inner.rate_pack.exit_byte_rate = 10; c_au_node.inner.rate_pack.exit_service_rate = 10; let a_fr_key = &subject.neighborhood_database.add_node(a_fr_node).unwrap(); @@ -4836,15 +4825,15 @@ mod tests { .clone(); let a_fr = &subject .neighborhood_database - .add_node(make_node_record(2345, true)) + .add_node(make_node_record_cc(2345, true, "FR")) .unwrap(); let b_fr = &subject .neighborhood_database - .add_node(make_node_record(5678, true)) + .add_node(make_node_record_cc(5678, true, "FR")) .unwrap(); let c_au = &subject .neighborhood_database - .add_node(make_node_record(1234, true)) + .add_node(make_node_record_cc(1234, true, "AU")) .unwrap(); subject .neighborhood_database @@ -5857,9 +5846,9 @@ mod tests { new_ip: new_public_ip, }); - assert_eq!( + assert_ne!( subject.neighborhood_database.root().inner.country_code_opt, - Some("US".to_string()) + Some("AU".to_string()) ); assert_eq!( subject.neighborhood_database.root().inner.country_code_opt, @@ -6198,8 +6187,8 @@ mod tests { None, ); let mut db = db_from_node(&this_node); - let far_neighbor = make_node_record(1324, true); - let gossip_neighbor = make_node_record(4657, true); + let far_neighbor = make_node_record_cc(1324, true, "AU"); + let gossip_neighbor = make_node_record_cc(4657, true, "US"); db.add_node(far_neighbor.clone()).unwrap(); db.add_node(gossip_neighbor.clone()).unwrap(); db.add_arbitrary_full_neighbor(this_node.public_key(), gossip_neighbor.public_key()); diff --git a/node/src/neighborhood/neighborhood_database.rs b/node/src/neighborhood/neighborhood_database.rs index ddb0fb879..e7345e687 100644 --- a/node/src/neighborhood/neighborhood_database.rs +++ b/node/src/neighborhood/neighborhood_database.rs @@ -535,7 +535,6 @@ mod tests { this_node.inner.country_code_opt = Some("AU".to_string()); this_node.metadata.node_location_opt = Some(NodeLocation { country_code: "AU".to_string(), - free_world_bit: true, }); this_node.resign(); let one_node = make_node_record(4567, true); @@ -872,7 +871,6 @@ mod tests { old_node.inner.country_code_opt = Some("AU".to_string()); old_node.metadata.node_location_opt = Some(NodeLocation { country_code: "AU".to_string(), - free_world_bit: true, }); old_node.resign(); diff --git a/node/src/neighborhood/node_location.rs b/node/src/neighborhood/node_location.rs index 08afb1704..4aba84516 100644 --- a/node/src/neighborhood/node_location.rs +++ b/node/src/neighborhood/node_location.rs @@ -7,7 +7,6 @@ use std::net::IpAddr; #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct NodeLocation { pub country_code: String, - pub free_world_bit: bool, } pub fn get_node_location(ip_opt: Option) -> Option { @@ -16,7 +15,6 @@ pub fn get_node_location(ip_opt: Option) -> Option { let country_opt = CountryCodeFinder::find_country(&COUNTRY_CODE_FINDER, ip_addr); country_opt.map(|country| NodeLocation { country_code: country.iso3166.clone(), - free_world_bit: country.free_world, }) } None => None, @@ -34,7 +32,6 @@ mod tests { get_node_location(Some(IpAddr::V4(Ipv4Addr::new(125, 125, 125, 1)))).unwrap(); assert_eq!(node_location.country_code, "CN"); - assert_eq!(node_location.free_world_bit, false); } //TODO #479 check in From impl for AGR that construction of metadata contains proper country_code diff --git a/node/src/neighborhood/node_record.rs b/node/src/neighborhood/node_record.rs index d30d56e58..30125d94a 100644 --- a/node/src/neighborhood/node_record.rs +++ b/node/src/neighborhood/node_record.rs @@ -418,15 +418,6 @@ mod tests { actual_node_record.inner.country_code_opt, Some("AU".to_string()) ); - assert_eq!( - actual_node_record - .metadata - .node_location_opt - .as_ref() - .unwrap() - .free_world_bit, - true - ); expected_node_record.metadata.last_update = actual_node_record.metadata.last_update; assert_eq!(actual_node_record, expected_node_record); } diff --git a/node/src/test_utils/neighborhood_test_utils.rs b/node/src/test_utils/neighborhood_test_utils.rs index 1b0af210f..0ba0226aa 100644 --- a/node/src/test_utils/neighborhood_test_utils.rs +++ b/node/src/test_utils/neighborhood_test_utils.rs @@ -15,6 +15,7 @@ use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::wallet::Wallet; use crate::test_utils::*; use ethereum_types::H160; +use ip_country_lib::country_finder::COUNTRY_CODE_FINDER; use masq_lib::blockchains::chains::Chain; use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use std::convert::TryFrom; @@ -24,41 +25,6 @@ use std::net::Ipv4Addr; pub const MIN_HOPS_FOR_TEST: Hops = DEFAULT_MIN_HOPS; pub const DB_PATCH_SIZE_FOR_TEST: u8 = DEFAULT_MIN_HOPS as u8; -lazy_static! { - pub static ref COUNTRY_CODE_DIGEST: Vec<(IpAddr, String, bool)> = vec![ - ( - IpAddr::V4(Ipv4Addr::new(123, 123, 123, 123)), - "CN".to_string(), - false - ), - ( - IpAddr::V4(Ipv4Addr::new(0, 0, 0, 123)), - "US".to_string(), - true - ), - ( - IpAddr::V4(Ipv4Addr::new(99, 99, 99, 99)), - "FR".to_string(), - true - ), - ( - IpAddr::V4(Ipv4Addr::new(3, 3, 3, 3)), - "AU".to_string(), - true - ), - ( - IpAddr::V4(Ipv4Addr::new(101, 0, 0, 255)), - "AU".to_string(), - true - ), - ( - IpAddr::V4(Ipv4Addr::new(255, 0, 0, 220)), - "FR".to_string(), - true - ), - ]; -} - impl From<(&NeighborhoodDatabase, &PublicKey, bool)> for AccessibleGossipRecord { fn from( (database, public_key, reveal_node_addr): (&NeighborhoodDatabase, &PublicKey, bool), @@ -85,15 +51,11 @@ pub fn make_node_record(n: u16, has_ip: bool) -> NodeRecord { let key = PublicKey::new(&[seg1, seg2, seg3, seg4]); let ip_addr = make_segmented_ip(seg1, seg2, seg3, seg4); let node_addr = NodeAddr::new(&ip_addr, &[n % 10000]); - let (_ip, country_code, free_world_bit) = pick_country_code_record(n); + let country_opt = COUNTRY_CODE_FINDER.find_country(ip_addr); let location_opt = match has_ip { - true => match country_code.is_empty() { - false => Some(NodeLocation { - country_code, - free_world_bit, - }), - true => None, - }, + true => country_opt.map(|country| NodeLocation { + country_code: country.iso3166.clone(), + }), false => None, }; @@ -107,8 +69,21 @@ pub fn make_node_record(n: u16, has_ip: bool) -> NodeRecord { ) } -pub fn pick_country_code_record(n: u16) -> (IpAddr, String, bool) { - COUNTRY_CODE_DIGEST[n as usize % COUNTRY_CODE_DIGEST.len()].clone() +pub fn make_node_record_cc(n: u16, has_ip: bool, cc: &str) -> NodeRecord { + let (seg1, seg2, seg3, seg4) = make_segments(n); + let key = PublicKey::new(&[seg1, seg2, seg3, seg4]); + let ip_addr = make_segmented_ip(seg1, seg2, seg3, seg4); + let node_addr = NodeAddr::new(&ip_addr, &[n % 10000]); + let location_opt = Some(NodeLocation { country_code: cc.to_string() }); + + NodeRecord::new_for_tests( + &key, + if has_ip { Some(&node_addr) } else { None }, + u64::from(n), + true, + true, + location_opt, + ) } pub fn make_node_record_f( From 71f222b229cc025a92b2da288c1665ed1b997cf4 Mon Sep 17 00:00:00 2001 From: czarte Date: Thu, 24 Apr 2025 19:32:21 +0200 Subject: [PATCH 2/5] fixes country_code on tests, introduced make_node_record_cc --- ip_country/src/country_finder.rs | 2 +- node/src/neighborhood/gossip.rs | 13 +++---- node/src/neighborhood/gossip_acceptor.rs | 10 ++---- node/src/neighborhood/gossip_producer.rs | 3 +- .../src/neighborhood/neighborhood_database.rs | 12 +++---- node/src/neighborhood/node_location.rs | 2 +- .../src/test_utils/neighborhood_test_utils.rs | 34 +++++++++++++++++++ 7 files changed, 50 insertions(+), 26 deletions(-) diff --git a/ip_country/src/country_finder.rs b/ip_country/src/country_finder.rs index 2c55a3e93..a6a964ea4 100644 --- a/ip_country/src/country_finder.rs +++ b/ip_country/src/country_finder.rs @@ -15,7 +15,7 @@ lazy_static! { } pub struct CountryCodeFinder { - ipv4: Vec, + pub ipv4: Vec, ipv6: Vec, } diff --git a/node/src/neighborhood/gossip.rs b/node/src/neighborhood/gossip.rs index cae5007cd..5177ecdef 100644 --- a/node/src/neighborhood/gossip.rs +++ b/node/src/neighborhood/gossip.rs @@ -513,9 +513,7 @@ pub fn regenerate_signed_gossip( mod tests { use super::super::gossip::GossipBuilder; use super::*; - use crate::test_utils::neighborhood_test_utils::{ - db_from_node, make_node_record, make_node_record_f, - }; + use crate::test_utils::neighborhood_test_utils::{db_from_node, make_node_record, make_node_record_cc, make_node_record_f}; use crate::test_utils::{assert_string_contains, vec_to_btset}; use std::str::FromStr; @@ -671,7 +669,7 @@ mod tests { #[test] fn gossip_node_record_is_debug_formatted_to_be_human_readable() { - let node = make_node_record(1234, true); + let node = make_node_record_cc(1234, true, "AU"); let mut db = db_from_node(&node); db.root_mut().increment_version(); db.root_mut().increment_version(); @@ -737,12 +735,11 @@ Length: 4 (0x4) bytes #[test] fn to_dot_graph_returns_gossip_in_dotgraph_format() { - let mut source_node = make_node_record(1234, true); + let mut source_node = make_node_record_cc(1234, true, "AU"); source_node.inner.public_key = PublicKey::new(&b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[..]); - let mut target_node = make_node_record(2345, true); + let mut target_node = make_node_record_cc(2345, true, "FR"); target_node.inner.public_key = PublicKey::new(&b"ZYXWVUTSRQPONMLKJIHGFEDCBA"[..]); - let mut neighbor = make_node_record(3456, false); - neighbor.inner.country_code_opt = Some("FR".to_string()); + let neighbor = make_node_record_cc(3456, false, "FR"); let mut db = db_from_node(&source_node); db.add_node(target_node.clone()).unwrap(); db.add_node(neighbor.clone()).unwrap(); diff --git a/node/src/neighborhood/gossip_acceptor.rs b/node/src/neighborhood/gossip_acceptor.rs index 46f1d4140..bde4a6e7a 100644 --- a/node/src/neighborhood/gossip_acceptor.rs +++ b/node/src/neighborhood/gossip_acceptor.rs @@ -1427,11 +1427,7 @@ mod tests { use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::neighborhood::{ConnectionProgressEvent, ConnectionProgressMessage}; use crate::sub_lib::utils::time_t_timestamp; - use crate::test_utils::neighborhood_test_utils::{ - db_from_node, gossip_about_nodes_from_database, linearly_connect_nodes, - make_meaningless_db, make_node_record, make_node_record_f, make_node_records, - public_keys_from_node_records, DB_PATCH_SIZE_FOR_TEST, - }; + use crate::test_utils::neighborhood_test_utils::{db_from_node, gossip_about_nodes_from_database, linearly_connect_nodes, make_meaningless_db, make_node_record, make_node_record_cc, make_node_record_f, make_node_records, public_keys_from_node_records, DB_PATCH_SIZE_FOR_TEST}; use crate::test_utils::unshared_test_utils::make_cpm_recipient; use crate::test_utils::{assert_contains, main_cryptde, vec_to_set}; use actix::System; @@ -2442,8 +2438,8 @@ mod tests { let src_root = make_node_record(1234, true); let dest_root = make_node_record(2345, true); let mut src_db = db_from_node(&src_root); - let node_a_fr = make_node_record(5678, true); - let node_b_us = make_node_record(4567, true); + let node_a_fr = make_node_record_cc(5678, true, "FR"); + let node_b_us = make_node_record_cc(4567, true, "US"); let mut dest_db = db_from_node(&dest_root); dest_db.add_node(src_root.clone()).unwrap(); dest_db.add_arbitrary_full_neighbor(dest_root.public_key(), src_root.public_key()); diff --git a/node/src/neighborhood/gossip_producer.rs b/node/src/neighborhood/gossip_producer.rs index 85d9cdc06..87e70f964 100644 --- a/node/src/neighborhood/gossip_producer.rs +++ b/node/src/neighborhood/gossip_producer.rs @@ -336,8 +336,7 @@ mod tests { #[test] fn produce_debut_creates_a_gossip_to_a_target_about_ourselves_when_accepting_connections() { - let mut our_node_record: NodeRecord = make_node_record(7771, true); - our_node_record.inner.country_code_opt = Some("US".to_string()); + let our_node_record: NodeRecord = make_node_record(7771, true); let db = db_from_node(&our_node_record); let subject = GossipProducerReal::new(); diff --git a/node/src/neighborhood/neighborhood_database.rs b/node/src/neighborhood/neighborhood_database.rs index e7345e687..46c33362c 100644 --- a/node/src/neighborhood/neighborhood_database.rs +++ b/node/src/neighborhood/neighborhood_database.rs @@ -389,9 +389,7 @@ mod tests { use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::utils::time_t_timestamp; use crate::test_utils::assert_string_contains; - use crate::test_utils::neighborhood_test_utils::{ - db_from_node, make_node_record, make_segmented_ip, make_segments, - }; + use crate::test_utils::neighborhood_test_utils::{db_from_node, make_node_record, make_node_record_cc, make_segmented_ip, make_segments}; use masq_lib::constants::DEFAULT_CHAIN; use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use std::iter::FromIterator; @@ -812,10 +810,10 @@ mod tests { #[test] fn database_can_be_pretty_printed_to_dot_format() { - let this_node = make_node_record(1234, true); // AQIDBA - let node_one = make_node_record(2345, true); // AgMEBQ - let node_two = make_node_record(3456, true); // AwQFBg - let node_three = make_node_record(4567, true); // BAUGBw + let this_node = make_node_record_cc(1234, true, "AU"); // AQIDBA + let node_one = make_node_record_cc(2345, true, "FR"); // AgMEBQ + let node_two = make_node_record_cc(3456, true, "CN"); // AwQFBg + let node_three = make_node_record_cc(4567, true, "US"); // BAUGBw let mut subject = db_from_node(&this_node); diff --git a/node/src/neighborhood/node_location.rs b/node/src/neighborhood/node_location.rs index 4aba84516..d8556d15c 100644 --- a/node/src/neighborhood/node_location.rs +++ b/node/src/neighborhood/node_location.rs @@ -31,7 +31,7 @@ mod tests { let node_location = get_node_location(Some(IpAddr::V4(Ipv4Addr::new(125, 125, 125, 1)))).unwrap(); - assert_eq!(node_location.country_code, "CN"); + assert_eq!(node_location.country_code, "CN"); } //TODO #479 check in From impl for AGR that construction of metadata contains proper country_code diff --git a/node/src/test_utils/neighborhood_test_utils.rs b/node/src/test_utils/neighborhood_test_utils.rs index 0ba0226aa..6ccd6edab 100644 --- a/node/src/test_utils/neighborhood_test_utils.rs +++ b/node/src/test_utils/neighborhood_test_utils.rs @@ -25,6 +25,40 @@ use std::net::Ipv4Addr; pub const MIN_HOPS_FOR_TEST: Hops = DEFAULT_MIN_HOPS; pub const DB_PATCH_SIZE_FOR_TEST: u8 = DEFAULT_MIN_HOPS as u8; +// pub static ref COUNTRY_CODE_DIGEST: Vec<(IpAddr, String, bool)> = vec![ +// ( +// IpAddr::V4(Ipv4Addr::new(123, 123, 123, 123)), +// "FR".to_string(), +// true +// ), +// ( +// IpAddr::V4(Ipv4Addr::new(0, 0, 0, 123)), +// "US".to_string(), +// true +// ), +// ( +// IpAddr::V4(Ipv4Addr::new(99, 99, 99, 99)), +// "FR".to_string(), +// true +// ), +// ( +// IpAddr::V4(Ipv4Addr::new(3, 3, 3, 3)), +// "AU".to_string(), +// true +// ), +// ( +// IpAddr::V4(Ipv4Addr::new(101, 0, 0, 255)), +// "AU".to_string(), +// true +// ), +// ( +// IpAddr::V4(Ipv4Addr::new(255, 0, 0, 220)), +// "FR".to_string(), +// true +// ), +// ]; +// } + impl From<(&NeighborhoodDatabase, &PublicKey, bool)> for AccessibleGossipRecord { fn from( (database, public_key, reveal_node_addr): (&NeighborhoodDatabase, &PublicKey, bool), From e670b466badc2addb3dd76295da68f71ce9c2f10 Mon Sep 17 00:00:00 2001 From: czarte Date: Mon, 28 Apr 2025 12:23:32 +0200 Subject: [PATCH 3/5] addressing commnets from review3 --- USER-INTERFACE-INTERFACE.md | 2 +- masq/src/commands/exit_location_command.rs | 10 ++- .../src/multinode_gossip.rs | 2 +- .../src/neighborhood_constructor.rs | 2 +- multinode_integration_tests/src/utils.rs | 2 +- .../tests/communication_failure_test.rs | 2 +- .../tests/neighbor_selection_test.rs | 2 +- node/src/neighborhood/gossip.rs | 4 +- node/src/neighborhood/gossip_acceptor.rs | 14 ++-- node/src/neighborhood/mod.rs | 77 ++++++++++++------- .../src/neighborhood/neighborhood_database.rs | 4 +- node/src/neighborhood/node_location.rs | 5 +- node/src/neighborhood/node_record.rs | 1 + .../src/test_utils/neighborhood_test_utils.rs | 4 +- 14 files changed, 80 insertions(+), 51 deletions(-) diff --git a/USER-INTERFACE-INTERFACE.md b/USER-INTERFACE-INTERFACE.md index 1903a95e5..07aa0d814 100644 --- a/USER-INTERFACE-INTERFACE.md +++ b/USER-INTERFACE-INTERFACE.md @@ -615,7 +615,7 @@ This command can be used in two ways which can't be combined: 1. If we use the command with showCountries set to true. 2. If we want to set an exit location. -In case 1. it retrieves information about the available countries in our neighborhood. In this case, other parameters are +In case 1. it retrieves information about the available countries in our neighborhood. Other parameters are ignored. In case 2. we must set showCountries to false and then configure fallbackRouting and exitLocations with our preferences. diff --git a/masq/src/commands/exit_location_command.rs b/masq/src/commands/exit_location_command.rs index 0ce6612fe..3eb3da985 100644 --- a/masq/src/commands/exit_location_command.rs +++ b/masq/src/commands/exit_location_command.rs @@ -491,8 +491,9 @@ pub mod tests { #[test] fn providing_show_countries_with_country_codes_fails() { - let result_expected = "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; - + let result_expected = + "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; + let result = SetExitLocationCommand::new(&[ "exit-location".to_string(), "--show-countries".to_string(), @@ -511,14 +512,15 @@ pub mod tests { #[test] fn providing_show_countries_with_fallback_routing_fails() { - let result_expected = "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; + let result_expected = + "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; let result = SetExitLocationCommand::new(&[ "exit-location".to_string(), "--show-countries".to_string(), "--fallback-routing".to_string(), ]) - .unwrap_err(); + .unwrap_err(); assert!( result.contains(result_expected), diff --git a/multinode_integration_tests/src/multinode_gossip.rs b/multinode_integration_tests/src/multinode_gossip.rs index 5c1f99321..868f0752d 100644 --- a/multinode_integration_tests/src/multinode_gossip.rs +++ b/multinode_integration_tests/src/multinode_gossip.rs @@ -2,8 +2,8 @@ use crate::masq_node::MASQNode; use masq_lib::blockchains::chains::Chain; use masq_lib::test_utils::utils::TEST_DEFAULT_MULTINODE_CHAIN; +use node_lib::neighborhood::gossip::AccessibleGossipRecord; use node_lib::neighborhood::gossip::{GossipNodeRecord, Gossip_0v1}; -use node_lib::neighborhood::AccessibleGossipRecord; use node_lib::sub_lib::cryptde::PublicKey; use node_lib::sub_lib::cryptde_null::CryptDENull; use node_lib::test_utils::vec_to_set; diff --git a/multinode_integration_tests/src/neighborhood_constructor.rs b/multinode_integration_tests/src/neighborhood_constructor.rs index 53a9d611e..d56d3a8eb 100644 --- a/multinode_integration_tests/src/neighborhood_constructor.rs +++ b/multinode_integration_tests/src/neighborhood_constructor.rs @@ -6,11 +6,11 @@ use crate::masq_node_cluster::MASQNodeCluster; use crate::masq_real_node::{make_consuming_wallet_info, NodeStartupConfigBuilder}; use crate::masq_real_node::{MASQRealNode, NodeStartupConfig}; use crate::multinode_gossip::{Standard, StandardBuilder}; +use node_lib::neighborhood::gossip::AccessibleGossipRecord; use node_lib::neighborhood::gossip::Gossip_0v1; use node_lib::neighborhood::gossip_producer::{GossipProducer, GossipProducerReal}; use node_lib::neighborhood::neighborhood_database::NeighborhoodDatabase; use node_lib::neighborhood::node_record::{NodeRecord, NodeRecordMetadata}; -use node_lib::neighborhood::AccessibleGossipRecord; use node_lib::sub_lib::cryptde::PublicKey; use node_lib::sub_lib::utils::time_t_timestamp; use node_lib::test_utils::neighborhood_test_utils::db_from_node; diff --git a/multinode_integration_tests/src/utils.rs b/multinode_integration_tests/src/utils.rs index d0cb6e988..fbb0341aa 100644 --- a/multinode_integration_tests/src/utils.rs +++ b/multinode_integration_tests/src/utils.rs @@ -12,9 +12,9 @@ use node_lib::database::db_initializer::{ }; use node_lib::database::rusqlite_wrappers::ConnectionWrapper; use node_lib::db_config::config_dao::{ConfigDao, ConfigDaoReal}; +use node_lib::neighborhood::gossip::AccessibleGossipRecord; use node_lib::neighborhood::node_location::get_node_location; use node_lib::neighborhood::node_record::NodeRecordInner_0v1; -use node_lib::neighborhood::AccessibleGossipRecord; use node_lib::sub_lib::cryptde::{CryptData, PlainData}; use std::collections::BTreeSet; use std::io::{ErrorKind, Read, Write}; diff --git a/multinode_integration_tests/tests/communication_failure_test.rs b/multinode_integration_tests/tests/communication_failure_test.rs index 59e37eb22..65d31dd4f 100644 --- a/multinode_integration_tests/tests/communication_failure_test.rs +++ b/multinode_integration_tests/tests/communication_failure_test.rs @@ -12,9 +12,9 @@ use multinode_integration_tests_lib::masq_real_node::{ }; use multinode_integration_tests_lib::neighborhood_constructor::construct_neighborhood; use node_lib::json_masquerader::JsonMasquerader; +use node_lib::neighborhood::gossip::AccessibleGossipRecord; use node_lib::neighborhood::neighborhood_database::NeighborhoodDatabase; use node_lib::neighborhood::node_record::NodeRecord; -use node_lib::neighborhood::AccessibleGossipRecord; use node_lib::sub_lib::cryptde::{CryptDE, PublicKey}; use node_lib::sub_lib::cryptde_null::CryptDENull; use node_lib::sub_lib::hopper::{ diff --git a/multinode_integration_tests/tests/neighbor_selection_test.rs b/multinode_integration_tests/tests/neighbor_selection_test.rs index b3c217417..225713ba5 100644 --- a/multinode_integration_tests/tests/neighbor_selection_test.rs +++ b/multinode_integration_tests/tests/neighbor_selection_test.rs @@ -9,10 +9,10 @@ use multinode_integration_tests_lib::multinode_gossip::{ use multinode_integration_tests_lib::neighborhood_constructor::{ construct_neighborhood, do_not_modify_config, }; +use node_lib::neighborhood::gossip::AccessibleGossipRecord; use node_lib::neighborhood::gossip::GossipBuilder; use node_lib::neighborhood::neighborhood_database::NeighborhoodDatabase; use node_lib::neighborhood::node_record::NodeRecord; -use node_lib::neighborhood::AccessibleGossipRecord; use node_lib::sub_lib::cryptde::PublicKey; use node_lib::sub_lib::neighborhood::GossipFailure_0v1; use node_lib::test_utils::neighborhood_test_utils::{db_from_node, make_node_record}; diff --git a/node/src/neighborhood/gossip.rs b/node/src/neighborhood/gossip.rs index 5177ecdef..71c0b32bc 100644 --- a/node/src/neighborhood/gossip.rs +++ b/node/src/neighborhood/gossip.rs @@ -513,7 +513,9 @@ pub fn regenerate_signed_gossip( mod tests { use super::super::gossip::GossipBuilder; use super::*; - use crate::test_utils::neighborhood_test_utils::{db_from_node, make_node_record, make_node_record_cc, make_node_record_f}; + use crate::test_utils::neighborhood_test_utils::{ + db_from_node, make_node_record, make_node_record_cc, make_node_record_f, + }; use crate::test_utils::{assert_string_contains, vec_to_btset}; use std::str::FromStr; diff --git a/node/src/neighborhood/gossip_acceptor.rs b/node/src/neighborhood/gossip_acceptor.rs index bde4a6e7a..d39f86f52 100644 --- a/node/src/neighborhood/gossip_acceptor.rs +++ b/node/src/neighborhood/gossip_acceptor.rs @@ -1427,7 +1427,11 @@ mod tests { use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::neighborhood::{ConnectionProgressEvent, ConnectionProgressMessage}; use crate::sub_lib::utils::time_t_timestamp; - use crate::test_utils::neighborhood_test_utils::{db_from_node, gossip_about_nodes_from_database, linearly_connect_nodes, make_meaningless_db, make_node_record, make_node_record_cc, make_node_record_f, make_node_records, public_keys_from_node_records, DB_PATCH_SIZE_FOR_TEST}; + use crate::test_utils::neighborhood_test_utils::{ + db_from_node, gossip_about_nodes_from_database, linearly_connect_nodes, + make_meaningless_db, make_node_record, make_node_record_cc, make_node_record_f, + make_node_records, public_keys_from_node_records, DB_PATCH_SIZE_FOR_TEST, + }; use crate::test_utils::unshared_test_utils::make_cpm_recipient; use crate::test_utils::{assert_contains, main_cryptde, vec_to_set}; use actix::System; @@ -1747,11 +1751,9 @@ mod tests { .unwrap(); let (dest_public_key, dest_node_addr) = match counter_debut { - GossipAcceptanceResult::Reply( - _, - ref dest_public_key, - ref dest_node_addr, - ) => (dest_public_key, dest_node_addr), + GossipAcceptanceResult::Reply(_, ref dest_public_key, ref dest_node_addr) => { + (dest_public_key, dest_node_addr) + } x => panic!("Expected Reply, got {:?}", x), }; assert_eq!(dest_public_key, new_debutant.public_key()); diff --git a/node/src/neighborhood/mod.rs b/node/src/neighborhood/mod.rs index 83ac28f2f..2275a10a8 100644 --- a/node/src/neighborhood/mod.rs +++ b/node/src/neighborhood/mod.rs @@ -60,9 +60,7 @@ use gossip_producer::GossipProducer; use gossip_producer::GossipProducerReal; use itertools::Itertools; use masq_lib::blockchains::chains::Chain; -use masq_lib::constants::{ - EXIT_COUNTRY_MISSING_COUNTRIES_ERROR, PAYLOAD_ZERO_SIZE, -}; +use masq_lib::constants::{EXIT_COUNTRY_MISSING_COUNTRIES_ERROR, PAYLOAD_ZERO_SIZE}; use masq_lib::crash_point::CrashPoint; use masq_lib::exit_locations::ExitLocationSet; use masq_lib::logger::Logger; @@ -562,7 +560,7 @@ impl Neighborhood { self.user_exit_preferences.locations_opt.clone() { for exit_location in &exit_locations_by_priority { - self.enrich_exit_countries_returns_missing(&exit_location.country_codes); + self.enrich_exit_countries_and_return_missing(&exit_location.country_codes); } self.set_country_undesirability_and_exit_countries(&exit_locations_by_priority); } @@ -1249,13 +1247,17 @@ impl Neighborhood { direction: RouteDirection, ) -> bool { self.user_exit_preferences.fallback_preference == FallbackPreference::Nothing - || (self.user_exit_preferences.fallback_preference - == FallbackPreference::ExitCountryWithFallback - && self.validate_country_code_when_fallback_routing(last_node_key)) + || self.is_fallback_and_last_node_qualifies(last_node_key) || research_neighborhood || direction == RouteDirection::Back } + fn is_fallback_and_last_node_qualifies(&self, last_node_key: &PublicKey) -> bool { + self.user_exit_preferences.fallback_preference + == FallbackPreference::ExitCountryWithFallback + && self.validate_country_code_when_fallback_routing(last_node_key) + } + fn compute_undesirability( node_record: &NodeRecord, payload_size: u64, @@ -1816,8 +1818,9 @@ impl Neighborhood { .into_iter() .map(|cc| { let requested_country_codes = &cc.country_codes; - countries_not_in_neighborhood - .extend(self.enrich_exit_countries_returns_missing(requested_country_codes)); + countries_not_in_neighborhood.extend( + self.enrich_exit_countries_and_return_missing(requested_country_codes), + ); ExitLocation { country_codes: cc.country_codes, priority: cc.priority, @@ -1828,7 +1831,10 @@ impl Neighborhood { ) } - fn enrich_exit_countries_returns_missing(&mut self, country_codes: &Vec) -> Vec { + fn enrich_exit_countries_and_return_missing( + &mut self, + country_codes: &Vec, + ) -> Vec { let mut countries_not_in_neighborhood = vec![]; for code in country_codes { if self.code_in_db_countries_or_fallback_active(code) { @@ -1978,7 +1984,7 @@ impl Neighborhood { warning!(self.logger, "Received shutdown notification for stream to {}, but no Node with that IP is in the database - ignoring", msg.peer_addr.ip()); return; } - Some(n) => (n.public_key().clone()), + Some(n) => n.public_key().clone(), }; self.remove_neighbor(&neighbor_key, &msg.peer_addr); } @@ -2072,7 +2078,8 @@ pub enum FallbackPreference { // fallback_preference is enum, that controls whether we want to strictly prohibit exit_location to nodes // with requested country_codes, or we accept other locations in case requested country is unavailable // locations_opt is Optional Vec of ExitLocation, it is set to Some(Vec) from users input, -// where ExitLocation is set of countries with same priority +// where ExitLocation is a set of countries with the same priority. None is state, when user did not set any +// country for exit at all. // db_countries is set of country_codes of all possible exit_nodes in our Neighborhood DB, is used to // persist those information in case, user want to see, which country he can select for exit #[derive(Clone, Debug)] @@ -2179,9 +2186,9 @@ mod tests { CountryGroups, ToMessageBody, UiConnectionChangeBroadcast, UiConnectionStage, }; use masq_lib::test_utils::utils::{ensure_node_home_directory_exists, TEST_DEFAULT_CHAIN}; + use masq_lib::ui_gateway::MessageBody; use masq_lib::ui_gateway::MessagePath::Conversation; use masq_lib::ui_gateway::MessageTarget; - use masq_lib::ui_gateway::{MessageBody, MessagePath}; use masq_lib::utils::running_test; use crate::db_config::persistent_configuration::PersistentConfigError; @@ -2206,7 +2213,12 @@ mod tests { use crate::test_utils::assert_contains; use crate::test_utils::make_meaningless_route; use crate::test_utils::make_wallet; - use crate::test_utils::neighborhood_test_utils::{cryptdes_from_node_records, db_from_node, linearly_connect_nodes, make_global_cryptde_node_record, make_ip, make_node, make_node_descriptor, make_node_record, make_node_record_cc, make_node_record_f, make_node_records, neighborhood_from_nodes, MIN_HOPS_FOR_TEST}; + use crate::test_utils::neighborhood_test_utils::{ + cryptdes_from_node_records, db_from_node, linearly_connect_nodes, + make_global_cryptde_node_record, make_ip, make_node, make_node_descriptor, + make_node_record, make_node_record_cc, make_node_record_f, make_node_records, + neighborhood_from_nodes, MIN_HOPS_FOR_TEST, + }; use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock; use crate::test_utils::rate_pack; use crate::test_utils::recorder::make_recorder; @@ -3647,22 +3659,25 @@ mod tests { subject .neighborhood_database .add_arbitrary_full_neighbor(root_node_ch.public_key(), neighbor_one_au.public_key()); - subject - .neighborhood_database - .add_arbitrary_full_neighbor(neighbor_one_au.public_key(), neighbor_two_fr.public_key()); - subject - .neighborhood_database - .add_arbitrary_full_neighbor(neighbor_two_fr.public_key(), neighbor_three_cn.public_key()); - subject - .neighborhood_database - .add_arbitrary_full_neighbor(neighbor_three_cn.public_key(), neighbor_four_us.public_key()); + subject.neighborhood_database.add_arbitrary_full_neighbor( + neighbor_one_au.public_key(), + neighbor_two_fr.public_key(), + ); + subject.neighborhood_database.add_arbitrary_full_neighbor( + neighbor_two_fr.public_key(), + neighbor_three_cn.public_key(), + ); + subject.neighborhood_database.add_arbitrary_full_neighbor( + neighbor_three_cn.public_key(), + neighbor_four_us.public_key(), + ); subject.user_exit_preferences.db_countries = subject.init_db_countries(); let exit_locations_by_priority = vec![ExitLocation { country_codes: vec!["FR".to_string(), "US".to_string()], priority: 1, }]; for exit_location in &exit_locations_by_priority { - subject.enrich_exit_countries_returns_missing(&exit_location.country_codes); + subject.enrich_exit_countries_and_return_missing(&exit_location.country_codes); } subject.user_exit_preferences.fallback_preference = FallbackPreference::ExitCountryNoFallback; @@ -3917,7 +3932,7 @@ mod tests { recorder_result.get_record::(0).body, MessageBody { opcode: "exitLocation".to_string(), - path: MessagePath::Conversation(234), + path: Conversation(234), payload: Ok(payload_message.to_string()) } ); @@ -4069,7 +4084,7 @@ mod tests { .body, MessageBody { opcode: "exitLocation".to_string(), - path: MessagePath::Conversation(123), + path: Conversation(123), payload: Err((9223372036854775816, "CZ, SK, IN".to_string(),)) } ); @@ -4805,8 +4820,14 @@ mod tests { subject.handle_exit_location_message(message, 0, 0); let subject_min_hops = 2; - let route_au = - subject.find_best_route_segment(root_key, None, subject_min_hops, 10000, RouteDirection::Over, None); + let route_au = subject.find_best_route_segment( + root_key, + None, + subject_min_hops, + 10000, + RouteDirection::Over, + None, + ); let exit_node = cdb.node_by_key(&route_au.as_ref().unwrap().last().unwrap()); assert_eq!( diff --git a/node/src/neighborhood/neighborhood_database.rs b/node/src/neighborhood/neighborhood_database.rs index 46c33362c..1b7ce2947 100644 --- a/node/src/neighborhood/neighborhood_database.rs +++ b/node/src/neighborhood/neighborhood_database.rs @@ -389,7 +389,9 @@ mod tests { use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::utils::time_t_timestamp; use crate::test_utils::assert_string_contains; - use crate::test_utils::neighborhood_test_utils::{db_from_node, make_node_record, make_node_record_cc, make_segmented_ip, make_segments}; + use crate::test_utils::neighborhood_test_utils::{ + db_from_node, make_node_record, make_node_record_cc, make_segmented_ip, make_segments, + }; use masq_lib::constants::DEFAULT_CHAIN; use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use std::iter::FromIterator; diff --git a/node/src/neighborhood/node_location.rs b/node/src/neighborhood/node_location.rs index d8556d15c..8b9764e4e 100644 --- a/node/src/neighborhood/node_location.rs +++ b/node/src/neighborhood/node_location.rs @@ -31,9 +31,6 @@ mod tests { let node_location = get_node_location(Some(IpAddr::V4(Ipv4Addr::new(125, 125, 125, 1)))).unwrap(); - assert_eq!(node_location.country_code, "CN"); + assert_eq!(node_location.country_code, "CN"); } - - //TODO #479 check in From impl for AGR that construction of metadata contains proper country_code - } diff --git a/node/src/neighborhood/node_record.rs b/node/src/neighborhood/node_record.rs index 30125d94a..bec5631a0 100644 --- a/node/src/neighborhood/node_record.rs +++ b/node/src/neighborhood/node_record.rs @@ -295,6 +295,7 @@ impl NodeRecord { } } +//TODO #479 check constructed metadata contains proper country_code impl From for NodeRecord { fn from(agr: AccessibleGossipRecord) -> Self { let ip_add_opt = agr diff --git a/node/src/test_utils/neighborhood_test_utils.rs b/node/src/test_utils/neighborhood_test_utils.rs index 6ccd6edab..27051e0b3 100644 --- a/node/src/test_utils/neighborhood_test_utils.rs +++ b/node/src/test_utils/neighborhood_test_utils.rs @@ -108,7 +108,9 @@ pub fn make_node_record_cc(n: u16, has_ip: bool, cc: &str) -> NodeRecord { let key = PublicKey::new(&[seg1, seg2, seg3, seg4]); let ip_addr = make_segmented_ip(seg1, seg2, seg3, seg4); let node_addr = NodeAddr::new(&ip_addr, &[n % 10000]); - let location_opt = Some(NodeLocation { country_code: cc.to_string() }); + let location_opt = Some(NodeLocation { + country_code: cc.to_string(), + }); NodeRecord::new_for_tests( &key, From 2e8c2b706771659e8294ee2d42c291b87e8dc0eb Mon Sep 17 00:00:00 2001 From: czarte Date: Mon, 28 Apr 2025 12:30:34 +0200 Subject: [PATCH 4/5] remove pub from CountryCodeFinder member, and remove commented out code --- ip_country/src/country_finder.rs | 2 +- .../src/test_utils/neighborhood_test_utils.rs | 34 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/ip_country/src/country_finder.rs b/ip_country/src/country_finder.rs index a6a964ea4..2c55a3e93 100644 --- a/ip_country/src/country_finder.rs +++ b/ip_country/src/country_finder.rs @@ -15,7 +15,7 @@ lazy_static! { } pub struct CountryCodeFinder { - pub ipv4: Vec, + ipv4: Vec, ipv6: Vec, } diff --git a/node/src/test_utils/neighborhood_test_utils.rs b/node/src/test_utils/neighborhood_test_utils.rs index 27051e0b3..5ab073ca5 100644 --- a/node/src/test_utils/neighborhood_test_utils.rs +++ b/node/src/test_utils/neighborhood_test_utils.rs @@ -25,40 +25,6 @@ use std::net::Ipv4Addr; pub const MIN_HOPS_FOR_TEST: Hops = DEFAULT_MIN_HOPS; pub const DB_PATCH_SIZE_FOR_TEST: u8 = DEFAULT_MIN_HOPS as u8; -// pub static ref COUNTRY_CODE_DIGEST: Vec<(IpAddr, String, bool)> = vec![ -// ( -// IpAddr::V4(Ipv4Addr::new(123, 123, 123, 123)), -// "FR".to_string(), -// true -// ), -// ( -// IpAddr::V4(Ipv4Addr::new(0, 0, 0, 123)), -// "US".to_string(), -// true -// ), -// ( -// IpAddr::V4(Ipv4Addr::new(99, 99, 99, 99)), -// "FR".to_string(), -// true -// ), -// ( -// IpAddr::V4(Ipv4Addr::new(3, 3, 3, 3)), -// "AU".to_string(), -// true -// ), -// ( -// IpAddr::V4(Ipv4Addr::new(101, 0, 0, 255)), -// "AU".to_string(), -// true -// ), -// ( -// IpAddr::V4(Ipv4Addr::new(255, 0, 0, 220)), -// "FR".to_string(), -// true -// ), -// ]; -// } - impl From<(&NeighborhoodDatabase, &PublicKey, bool)> for AccessibleGossipRecord { fn from( (database, public_key, reveal_node_addr): (&NeighborhoodDatabase, &PublicKey, bool), From 669b67b66aae73f01cb382f5a5f3bd541f69a86b Mon Sep 17 00:00:00 2001 From: czarte Date: Mon, 28 Apr 2025 13:16:05 +0200 Subject: [PATCH 5/5] utilization of strings in clap test for show-countries --- masq/src/commands/exit_location_command.rs | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/masq/src/commands/exit_location_command.rs b/masq/src/commands/exit_location_command.rs index 3eb3da985..f52c50f96 100644 --- a/masq/src/commands/exit_location_command.rs +++ b/masq/src/commands/exit_location_command.rs @@ -491,9 +491,6 @@ pub mod tests { #[test] fn providing_show_countries_with_country_codes_fails() { - let result_expected = - "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; - let result = SetExitLocationCommand::new(&[ "exit-location".to_string(), "--show-countries".to_string(), @@ -502,19 +499,26 @@ pub mod tests { ]) .unwrap_err(); + let result_expected = + "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; + let expected_one = "show-countries"; + let expected_two = "country-codes"; assert!( result.contains(result_expected), "result was {:?}, but expected {:?}", result, result_expected, ); + assert!( + result.contains(expected_one) || result.contains(expected_two), + "result was not containing neither of those {:?}, nor {:?}", + expected_one, + expected_two, + ); } #[test] fn providing_show_countries_with_fallback_routing_fails() { - let result_expected = - "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; - let result = SetExitLocationCommand::new(&[ "exit-location".to_string(), "--show-countries".to_string(), @@ -522,11 +526,21 @@ pub mod tests { ]) .unwrap_err(); + let result_expected = + "cannot be used with one or more of the other specified arguments\n\nUSAGE:\n"; + let expected_one = "show-countries"; + let expected_two = "fallback-routing"; assert!( result.contains(result_expected), "result was {:?}, but expected {:?}", result, result_expected, ); + assert!( + result.contains(expected_one) || result.contains(expected_two), + "result was not containing neither of those {:?}, nor {:?}", + expected_one, + expected_two, + ); } }