diff options
| -rw-r--r-- | src/client.rs | 31 | ||||
| -rw-r--r-- | src/key_handling/users.rs | 320 | ||||
| -rw-r--r-- | test_utils/src/lib.rs | 19 | ||||
| -rw-r--r-- | tests/login.rs | 831 |
4 files changed, 727 insertions, 474 deletions
diff --git a/src/client.rs b/src/client.rs index 5ddf742..929f19a 100644 --- a/src/client.rs +++ b/src/client.rs | |||
| @@ -101,14 +101,7 @@ impl Connect for Client { | |||
| 101 | filters.clone(), | 101 | filters.clone(), |
| 102 | ) | 102 | ) |
| 103 | }) | 103 | }) |
| 104 | .map(|(relay, filters)| { | 104 | .map(|(relay, filters)| get_events_of(relay, filters)), |
| 105 | relay.get_events_of( | ||
| 106 | filters, | ||
| 107 | // 20 is nostr_sdk default | ||
| 108 | std::time::Duration::from_secs(20), | ||
| 109 | nostr_sdk::FilterOptions::ExitOnEOSE, | ||
| 110 | ) | ||
| 111 | }), | ||
| 112 | ) | 105 | ) |
| 113 | .await; | 106 | .await; |
| 114 | 107 | ||
| @@ -116,6 +109,24 @@ impl Connect for Client { | |||
| 116 | } | 109 | } |
| 117 | } | 110 | } |
| 118 | 111 | ||
| 112 | async fn get_events_of( | ||
| 113 | relay: &nostr_sdk::Relay, | ||
| 114 | filters: Vec<nostr::Filter>, | ||
| 115 | ) -> Result<Vec<Event>> { | ||
| 116 | if !relay.is_connected().await { | ||
| 117 | relay.connect(true).await; | ||
| 118 | } | ||
| 119 | relay | ||
| 120 | .get_events_of( | ||
| 121 | filters, | ||
| 122 | // 20 is nostr_sdk default | ||
| 123 | std::time::Duration::from_secs(20), | ||
| 124 | nostr_sdk::FilterOptions::ExitOnEOSE, | ||
| 125 | ) | ||
| 126 | .await | ||
| 127 | .context("failed to get events from relay") | ||
| 128 | } | ||
| 129 | |||
| 119 | #[derive(Default)] | 130 | #[derive(Default)] |
| 120 | pub struct Params { | 131 | pub struct Params { |
| 121 | pub keys: Option<nostr::Keys>, | 132 | pub keys: Option<nostr::Keys>, |
| @@ -133,9 +144,7 @@ impl Params { | |||
| 133 | } | 144 | } |
| 134 | } | 145 | } |
| 135 | 146 | ||
| 136 | fn get_dedup_events( | 147 | fn get_dedup_events(relay_results: Vec<Result<Vec<nostr::Event>>>) -> Vec<Event> { |
| 137 | relay_results: Vec<Result<Vec<nostr::Event>, nostr_sdk::relay::Error>>, | ||
| 138 | ) -> Vec<Event> { | ||
| 139 | let mut dedup_events: Vec<Event> = vec![]; | 148 | let mut dedup_events: Vec<Event> = vec![]; |
| 140 | for events in relay_results.into_iter().flatten() { | 149 | for events in relay_results.into_iter().flatten() { |
| 141 | for event in events { | 150 | for event in events { |
diff --git a/src/key_handling/users.rs b/src/key_handling/users.rs index 91519bc..a486296 100644 --- a/src/key_handling/users.rs +++ b/src/key_handling/users.rs | |||
| @@ -143,7 +143,8 @@ impl UserManagement for UserManager { | |||
| 143 | .clone()) | 143 | .clone()) |
| 144 | } | 144 | } |
| 145 | /// get UserRef fetching most recent user relays and metadata infomation | 145 | /// get UserRef fetching most recent user relays and metadata infomation |
| 146 | /// from relays | 146 | /// from |
| 147 | #[allow(clippy::too_many_lines)] | ||
| 147 | async fn get_user( | 148 | async fn get_user( |
| 148 | &self, | 149 | &self, |
| 149 | #[cfg(test)] client: &MockConnect, | 150 | #[cfg(test)] client: &MockConnect, |
| @@ -155,103 +156,127 @@ impl UserManagement for UserManager { | |||
| 155 | .config_manager | 156 | .config_manager |
| 156 | .load() | 157 | .load() |
| 157 | .context("failed to load application config")?; | 158 | .context("failed to load application config")?; |
| 158 | let user_ref = cfg | 159 | let mut user_ref = cfg |
| 159 | .users | 160 | .users |
| 160 | .iter() | 161 | .iter() |
| 161 | .find(|u| u.public_key.eq(public_key)) | 162 | .find(|u| u.public_key.eq(public_key)) |
| 162 | .context(format!("pubkey isn't a current user: {public_key}"))?; | 163 | .context(format!("pubkey isn't a current user: {public_key}"))? |
| 164 | .clone(); | ||
| 163 | // return cache if last fetched was within X minutes | 165 | // return cache if last fetched was within X minutes |
| 164 | if !unix_timestamp_after_now_plus_secs( | 166 | if !unix_timestamp_after_now_plus_secs( |
| 165 | user_ref.last_checked, | 167 | user_ref.last_checked, |
| 166 | use_cache_unless_checked_more_than_x_secs_ago, | 168 | use_cache_unless_checked_more_than_x_secs_ago, |
| 167 | ) { | 169 | ) { |
| 168 | return Ok(user_ref.clone()); | 170 | return Ok(user_ref); |
| 169 | } | 171 | } |
| 170 | let events: Vec<Event> = match client | 172 | |
| 171 | .get_events( | 173 | let mut relays_to_search = if user_ref.relays.write().is_empty() { |
| 172 | if user_ref.relays.write().is_empty() { | 174 | client.get_fallback_relays().clone() |
| 173 | client.get_fallback_relays().clone() | 175 | } else { |
| 174 | } else { | 176 | user_ref.relays.write() |
| 175 | user_ref.relays.write() | ||
| 176 | }, | ||
| 177 | vec![ | ||
| 178 | nostr::Filter::default() | ||
| 179 | .author(public_key.to_string()) | ||
| 180 | .since(nostr::Timestamp::from(user_ref.metadata.created_at + 1)) | ||
| 181 | .kind(Kind::Metadata), | ||
| 182 | nostr::Filter::default() | ||
| 183 | .author(public_key.to_string()) | ||
| 184 | .since(nostr::Timestamp::from(user_ref.relays.created_at + 1)) | ||
| 185 | .kind(Kind::RelayList), | ||
| 186 | ], | ||
| 187 | ) | ||
| 188 | .await | ||
| 189 | { | ||
| 190 | Ok(events) => events, | ||
| 191 | Err(_) => { | ||
| 192 | // TODO error reporting | ||
| 193 | return Ok(user_ref.clone()); | ||
| 194 | } | ||
| 195 | }; | 177 | }; |
| 196 | 178 | ||
| 197 | let mut user_ref = user_ref.clone(); | 179 | let mut relays_searched: Vec<String> = vec![]; |
| 198 | 180 | ||
| 199 | user_ref.last_checked = SystemTime::now() | 181 | loop { |
| 200 | .duration_since(SystemTime::UNIX_EPOCH) | 182 | for r in &relays_to_search { |
| 201 | .context("system time should be after the year 1970")? | 183 | if !relays_searched.iter().any(|sr| r.eq(sr)) { |
| 202 | .as_secs(); | 184 | relays_searched.push(r.clone()); |
| 203 | 185 | } | |
| 204 | if let Some(new_metadata_event) = events | ||
| 205 | .iter() | ||
| 206 | .filter(|e| e.kind.eq(&nostr::Kind::Metadata) && e.pubkey.eq(public_key)) | ||
| 207 | .max_by_key(|e| e.created_at) | ||
| 208 | { | ||
| 209 | if new_metadata_event.created_at.as_u64() > user_ref.metadata.created_at { | ||
| 210 | let metadata = nostr::Metadata::from_json(new_metadata_event.content.clone()) | ||
| 211 | .context("metadata cannot be found in kind 0 event content")?; | ||
| 212 | user_ref.metadata = UserMetadata { | ||
| 213 | name: metadata | ||
| 214 | .name | ||
| 215 | .context("user metadata should always have name")?, | ||
| 216 | created_at: new_metadata_event.created_at.as_u64(), | ||
| 217 | }; | ||
| 218 | } | 186 | } |
| 219 | }; | ||
| 220 | 187 | ||
| 221 | if let Some(new_relays_event) = events | 188 | let events: Vec<Event> = match client |
| 222 | .iter() | 189 | .get_events( |
| 223 | .filter(|e| e.kind.eq(&nostr::Kind::RelayList) && e.pubkey.eq(public_key)) | 190 | relays_to_search, |
| 224 | .max_by_key(|e| e.created_at) | 191 | vec![ |
| 225 | { | 192 | nostr::Filter::default() |
| 226 | if new_relays_event.created_at.as_u64() > user_ref.relays.created_at { | 193 | .author(public_key.to_string()) |
| 227 | user_ref.relays = UserRelays { | 194 | .since(nostr::Timestamp::from(user_ref.metadata.created_at + 1)) |
| 228 | relays: new_relays_event | 195 | .kind(Kind::Metadata), |
| 229 | .tags | 196 | nostr::Filter::default() |
| 197 | .author(public_key.to_string()) | ||
| 198 | .since(nostr::Timestamp::from(user_ref.relays.created_at + 1)) | ||
| 199 | .kind(Kind::RelayList), | ||
| 200 | ], | ||
| 201 | ) | ||
| 202 | .await | ||
| 203 | { | ||
| 204 | Ok(events) => events, | ||
| 205 | Err(_) => { | ||
| 206 | return Ok(user_ref.clone()); | ||
| 207 | } | ||
| 208 | }; | ||
| 209 | |||
| 210 | user_ref.last_checked = SystemTime::now() | ||
| 211 | .duration_since(SystemTime::UNIX_EPOCH) | ||
| 212 | .context("system time should be after the year 1970")? | ||
| 213 | .as_secs(); | ||
| 214 | |||
| 215 | if let Some(new_metadata_event) = events | ||
| 216 | .iter() | ||
| 217 | .filter(|e| e.kind.eq(&nostr::Kind::Metadata) && e.pubkey.eq(public_key)) | ||
| 218 | .max_by_key(|e| e.created_at) | ||
| 219 | { | ||
| 220 | if new_metadata_event.created_at.as_u64() > user_ref.metadata.created_at { | ||
| 221 | let metadata = nostr::Metadata::from_json(new_metadata_event.content.clone()) | ||
| 222 | .context("metadata cannot be found in kind 0 event content")?; | ||
| 223 | user_ref.metadata = UserMetadata { | ||
| 224 | name: metadata | ||
| 225 | .name | ||
| 226 | .context("user metadata should always have name")?, | ||
| 227 | created_at: new_metadata_event.created_at.as_u64(), | ||
| 228 | }; | ||
| 229 | } | ||
| 230 | }; | ||
| 231 | |||
| 232 | if let Some(new_relays_event) = events | ||
| 233 | .iter() | ||
| 234 | .filter(|e| e.kind.eq(&nostr::Kind::RelayList) && e.pubkey.eq(public_key)) | ||
| 235 | .max_by_key(|e| e.created_at) | ||
| 236 | { | ||
| 237 | if new_relays_event.created_at.as_u64() > user_ref.relays.created_at { | ||
| 238 | let new_relay_list = UserRelays { | ||
| 239 | relays: new_relays_event | ||
| 240 | .tags | ||
| 241 | .iter() | ||
| 242 | .filter(|t| t.kind().eq(&nostr::TagKind::R)) | ||
| 243 | .map(|t| UserRelayRef { | ||
| 244 | url: t.as_vec()[1].clone(), | ||
| 245 | read: t.as_vec().len() == 2 || t.as_vec()[2].eq("read"), | ||
| 246 | write: t.as_vec().len() == 2 || t.as_vec()[2].eq("write"), | ||
| 247 | }) | ||
| 248 | .collect(), | ||
| 249 | created_at: new_relays_event.created_at.as_u64(), | ||
| 250 | }; | ||
| 251 | let new_relays: Vec<String> = new_relay_list | ||
| 252 | .write() | ||
| 230 | .iter() | 253 | .iter() |
| 231 | .filter(|t| t.kind().eq(&nostr::TagKind::R)) | 254 | .filter(|r| !relays_searched.iter().any(|or| r.eq(&or))) |
| 232 | .map(|t| UserRelayRef { | 255 | .map(std::clone::Clone::clone) |
| 233 | url: t.as_vec()[1].clone(), | 256 | .collect(); |
| 234 | read: t.as_vec().len() == 2 || t.as_vec()[2].eq("read"), | 257 | user_ref.relays = new_relay_list; |
| 235 | write: t.as_vec().len() == 2 || t.as_vec()[2].eq("write"), | 258 | |
| 236 | }) | 259 | if !new_relays.is_empty() { |
| 237 | .collect(), | 260 | relays_to_search = new_relays; |
| 238 | created_at: new_relays_event.created_at.as_u64(), | 261 | continue; |
| 239 | }; | 262 | } |
| 240 | } | 263 | } |
| 241 | }; | 264 | }; |
| 242 | 265 | ||
| 243 | // remove any duplicate entries for key before adding it to config | 266 | // remove any duplicate entries for key before adding it to config |
| 244 | let mut cfg = self.config_manager.load().context("failed to load application config to find and remove any old versions of the user's encrypted key")?; | 267 | let mut cfg = self.config_manager.load().context("failed to load application config to find and remove any old versions of the user's encrypted key")?; |
| 245 | cfg.users = cfg | 268 | cfg.users = cfg |
| 246 | .users | 269 | .users |
| 247 | .clone() | 270 | .clone() |
| 248 | .into_iter() | 271 | .into_iter() |
| 249 | .filter(|r| !r.public_key.eq(public_key)) | 272 | .filter(|r| !r.public_key.eq(public_key)) |
| 250 | .collect(); | 273 | .collect(); |
| 251 | cfg.users.push(user_ref.clone()); | 274 | cfg.users.push(user_ref.clone()); |
| 252 | self.config_manager | 275 | self.config_manager |
| 253 | .save(&cfg) | 276 | .save(&cfg) |
| 254 | .context("failed to save application configuration with new user details in")?; | 277 | .context("failed to save application configuration with new user details in")?; |
| 278 | break; | ||
| 279 | } | ||
| 255 | Ok(user_ref) | 280 | Ok(user_ref) |
| 256 | } | 281 | } |
| 257 | } | 282 | } |
| @@ -611,23 +636,33 @@ mod tests { | |||
| 611 | .clone() | 636 | .clone() |
| 612 | } | 637 | } |
| 613 | 638 | ||
| 639 | fn expected_userrelayrefs_write1() -> UserRelayRef { | ||
| 640 | UserRelayRef { | ||
| 641 | url: "wss://fredswrite1.relay".into(), | ||
| 642 | read: false, | ||
| 643 | write: true, | ||
| 644 | } | ||
| 645 | .clone() | ||
| 646 | } | ||
| 647 | |||
| 648 | fn expected_userrelayrefs_read_write1() -> UserRelayRef { | ||
| 649 | UserRelayRef { | ||
| 650 | url: "wss://fredsreadwrite.relay".into(), | ||
| 651 | read: true, | ||
| 652 | write: true, | ||
| 653 | } | ||
| 654 | .clone() | ||
| 655 | } | ||
| 656 | |||
| 614 | fn expected_userrelayrefs() -> Vec<UserRelayRef> { | 657 | fn expected_userrelayrefs() -> Vec<UserRelayRef> { |
| 615 | vec![ | 658 | vec![ |
| 616 | UserRelayRef { | 659 | expected_userrelayrefs_write1(), |
| 617 | url: "wss://fredswrite1.relay".into(), | ||
| 618 | read: false, | ||
| 619 | write: true, | ||
| 620 | }, | ||
| 621 | UserRelayRef { | 660 | UserRelayRef { |
| 622 | url: "wss://fredsread1.relay".into(), | 661 | url: "wss://fredsread1.relay".into(), |
| 623 | read: true, | 662 | read: true, |
| 624 | write: false, | 663 | write: false, |
| 625 | }, | 664 | }, |
| 626 | UserRelayRef { | 665 | expected_userrelayrefs_read_write1(), |
| 627 | url: "wss://fredsreadwrite.relay".into(), | ||
| 628 | read: true, | ||
| 629 | write: true, | ||
| 630 | }, | ||
| 631 | ] | 666 | ] |
| 632 | } | 667 | } |
| 633 | 668 | ||
| @@ -958,6 +993,107 @@ mod tests { | |||
| 958 | ))?; | 993 | ))?; |
| 959 | Ok(()) | 994 | Ok(()) |
| 960 | } | 995 | } |
| 996 | |||
| 997 | mod fetches_from_new_relays_discovered_in_incoming_relay_list { | ||
| 998 | use super::*; | ||
| 999 | |||
| 1000 | #[test] | ||
| 1001 | fn when_all_relays_in_list_are_new_finds_name() -> Result<()> { | ||
| 1002 | let mut m = MockUserManager::default(); | ||
| 1003 | let mut client = generate_mock_client(); | ||
| 1004 | m.config_manager.expect_load().returning(|| { | ||
| 1005 | Ok(MyConfig { | ||
| 1006 | users: vec![UserRef { | ||
| 1007 | relays: UserRelays { | ||
| 1008 | relays: vec![], | ||
| 1009 | created_at: 0, | ||
| 1010 | }, | ||
| 1011 | ..generate_standard_config().users[0].clone() | ||
| 1012 | }], | ||
| 1013 | ..generate_standard_config() | ||
| 1014 | }) | ||
| 1015 | }); | ||
| 1016 | m.config_manager.expect_save().returning(|_| Ok(())); | ||
| 1017 | client | ||
| 1018 | .expect_get_events() | ||
| 1019 | .times(2) | ||
| 1020 | .withf(move |relays, _filters| { | ||
| 1021 | fallback_relays().eq(relays) | ||
| 1022 | || UserRelays { | ||
| 1023 | relays: expected_userrelayrefs(), | ||
| 1024 | created_at: 0, | ||
| 1025 | } | ||
| 1026 | .write() | ||
| 1027 | .eq(relays) | ||
| 1028 | }) | ||
| 1029 | .returning(|relays, _| { | ||
| 1030 | if fallback_relays().eq(&relays) { | ||
| 1031 | Ok(vec![generate_relaylist_event()]) | ||
| 1032 | } else if (UserRelays { | ||
| 1033 | relays: expected_userrelayrefs(), | ||
| 1034 | created_at: 0, | ||
| 1035 | }) | ||
| 1036 | .write() | ||
| 1037 | .eq(&relays) | ||
| 1038 | { | ||
| 1039 | Ok(vec![generate_test_key_1_metadata_event("fred")]) | ||
| 1040 | } else { | ||
| 1041 | Ok(vec![]) | ||
| 1042 | } | ||
| 1043 | }); | ||
| 1044 | |||
| 1045 | let res = futures::executor::block_on(m.get_user( | ||
| 1046 | &client, | ||
| 1047 | &TEST_KEY_1_KEYS.public_key(), | ||
| 1048 | 5 * 60, // 5 mins ago | ||
| 1049 | ))?; | ||
| 1050 | assert_eq!(res.metadata.name, "fred"); | ||
| 1051 | Ok(()) | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | #[test] | ||
| 1055 | fn only_fetches_from_newly_added_relays() -> Result<()> { | ||
| 1056 | let mut m = MockUserManager::default(); | ||
| 1057 | let mut client = generate_mock_client(); | ||
| 1058 | m.config_manager.expect_load().returning(|| { | ||
| 1059 | Ok(MyConfig { | ||
| 1060 | users: vec![UserRef { | ||
| 1061 | relays: UserRelays { | ||
| 1062 | relays: vec![expected_userrelayrefs_write1()], | ||
| 1063 | created_at: 0, | ||
| 1064 | }, | ||
| 1065 | ..generate_standard_config().users[0].clone() | ||
| 1066 | }], | ||
| 1067 | ..generate_standard_config() | ||
| 1068 | }) | ||
| 1069 | }); | ||
| 1070 | m.config_manager.expect_save().returning(|_| Ok(())); | ||
| 1071 | client | ||
| 1072 | .expect_get_events() | ||
| 1073 | .times(2) | ||
| 1074 | .withf(move |relays, _filters| { | ||
| 1075 | vec![expected_userrelayrefs_write1().url].eq(relays) | ||
| 1076 | || vec![expected_userrelayrefs_read_write1().url].eq(relays) | ||
| 1077 | }) | ||
| 1078 | .returning(|relays, _| { | ||
| 1079 | if vec![expected_userrelayrefs_write1().url].eq(&relays) { | ||
| 1080 | Ok(vec![generate_relaylist_event()]) | ||
| 1081 | } else if vec![expected_userrelayrefs_read_write1().url].eq(&relays) { | ||
| 1082 | Ok(vec![generate_test_key_1_metadata_event("fred")]) | ||
| 1083 | } else { | ||
| 1084 | Ok(vec![]) | ||
| 1085 | } | ||
| 1086 | }); | ||
| 1087 | |||
| 1088 | let res = futures::executor::block_on(m.get_user( | ||
| 1089 | &client, | ||
| 1090 | &TEST_KEY_1_KEYS.public_key(), | ||
| 1091 | 5 * 60, // 5 mins ago | ||
| 1092 | ))?; | ||
| 1093 | assert_eq!(res.metadata.name, "fred"); | ||
| 1094 | Ok(()) | ||
| 1095 | } | ||
| 1096 | } | ||
| 961 | } | 1097 | } |
| 962 | 1098 | ||
| 963 | #[test] | 1099 | #[test] |
diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 2a06357..3cb5d65 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs | |||
| @@ -56,6 +56,25 @@ pub fn generate_test_key_1_relay_list_event() -> nostr::Event { | |||
| 56 | .unwrap() | 56 | .unwrap() |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | pub fn generate_test_key_1_relay_list_event_same_as_fallback() -> nostr::Event { | ||
| 60 | nostr::event::EventBuilder::new( | ||
| 61 | nostr::Kind::RelayList, | ||
| 62 | "", | ||
| 63 | &[ | ||
| 64 | nostr::Tag::RelayMetadata( | ||
| 65 | "ws://localhost:8051".into(), | ||
| 66 | Some(nostr::RelayMetadata::Write), | ||
| 67 | ), | ||
| 68 | nostr::Tag::RelayMetadata( | ||
| 69 | "ws://localhost:8052".into(), | ||
| 70 | Some(nostr::RelayMetadata::Write), | ||
| 71 | ), | ||
| 72 | ], | ||
| 73 | ) | ||
| 74 | .to_event(&TEST_KEY_1_KEYS) | ||
| 75 | .unwrap() | ||
| 76 | } | ||
| 77 | |||
| 59 | pub static TEST_KEY_2_NSEC: &str = | 78 | pub static TEST_KEY_2_NSEC: &str = |
| 60 | "nsec1ypglg6nj6ep0g2qmyfqcv2al502gje3jvpwye6mthmkvj93tqkesknv6qm"; | 79 | "nsec1ypglg6nj6ep0g2qmyfqcv2al502gje3jvpwye6mthmkvj93tqkesknv6qm"; |
| 61 | pub static TEST_KEY_2_NPUB: &str = | 80 | pub static TEST_KEY_2_NPUB: &str = |
diff --git a/tests/login.rs b/tests/login.rs index d565620..e6ead6b 100644 --- a/tests/login.rs +++ b/tests/login.rs | |||
| @@ -27,220 +27,343 @@ mod with_relays { | |||
| 27 | 27 | ||
| 28 | use super::*; | 28 | use super::*; |
| 29 | 29 | ||
| 30 | mod when_first_time_login { | 30 | mod when_user_relay_list_aligns_with_fallback_relays { |
| 31 | // this simplifies testing | ||
| 31 | use super::*; | 32 | use super::*; |
| 32 | 33 | ||
| 33 | // falls_back_to_fallback_relays - this is implict in the tests | 34 | mod when_first_time_login { |
| 35 | use super::*; | ||
| 34 | 36 | ||
| 35 | mod dislays_logged_in_with_correct_name { | 37 | // falls_back_to_fallback_relays - this is implict in the tests |
| 36 | 38 | ||
| 37 | use super::*; | 39 | mod dislays_logged_in_with_correct_name { |
| 38 | 40 | ||
| 39 | async fn run_test_displays_correct_name( | 41 | use super::*; |
| 40 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 41 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 42 | ) -> Result<()> { | ||
| 43 | let (mut r51, mut r52) = ( | ||
| 44 | Relay::new(8051, None, relay_listener1), | ||
| 45 | Relay::new(8052, None, relay_listener2), | ||
| 46 | ); | ||
| 47 | 42 | ||
| 48 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 43 | async fn run_test_displays_correct_name( |
| 49 | with_fresh_config(|| { | 44 | relay_listener1: Option<ListenerReqFunc<'_>>, |
| 50 | let mut p = CliTester::new(["login"]); | 45 | relay_listener2: Option<ListenerReqFunc<'_>>, |
| 46 | ) -> Result<()> { | ||
| 47 | let (mut r51, mut r52) = ( | ||
| 48 | Relay::new(8051, None, relay_listener1), | ||
| 49 | Relay::new(8052, None, relay_listener2), | ||
| 50 | ); | ||
| 51 | 51 | ||
| 52 | p.expect_input(EXPECTED_NSEC_PROMPT)? | 52 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 53 | .succeeds_with(TEST_KEY_1_NSEC)?; | 53 | with_fresh_config(|| { |
| 54 | let mut p = CliTester::new(["login"]); | ||
| 54 | 55 | ||
| 55 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | 56 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 56 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | 57 | .succeeds_with(TEST_KEY_1_NSEC)?; |
| 57 | .succeeds_with(TEST_PASSWORD)?; | ||
| 58 | 58 | ||
| 59 | p.expect("searching for your details...\r\n")?; | 59 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? |
| 60 | p.expect("\r")?; | 60 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? |
| 61 | .succeeds_with(TEST_PASSWORD)?; | ||
| 61 | 62 | ||
| 62 | p.expect_end_with("logged in as fred\r\n")?; | 63 | p.expect("searching for your details...\r\n")?; |
| 63 | for p in [51, 52] { | 64 | p.expect("\r")?; |
| 64 | shutdown_relay(8000 + p)?; | ||
| 65 | } | ||
| 66 | Ok(()) | ||
| 67 | }) | ||
| 68 | }); | ||
| 69 | 65 | ||
| 70 | // launch relay | 66 | p.expect_end_with("logged in as fred\r\n")?; |
| 71 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | 67 | for p in [51, 52] { |
| 68 | shutdown_relay(8000 + p)?; | ||
| 69 | } | ||
| 70 | Ok(()) | ||
| 71 | }) | ||
| 72 | }); | ||
| 72 | 73 | ||
| 73 | cli_tester_handle.join().unwrap()?; | 74 | // launch relay |
| 74 | Ok(()) | 75 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); |
| 75 | } | ||
| 76 | 76 | ||
| 77 | #[test] | 77 | cli_tester_handle.join().unwrap()?; |
| 78 | #[serial] | 78 | Ok(()) |
| 79 | fn when_latest_metadata_and_relay_list_on_all_relays() -> Result<()> { | 79 | } |
| 80 | futures::executor::block_on(run_test_displays_correct_name( | ||
| 81 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 82 | relay.respond_events( | ||
| 83 | client_id, | ||
| 84 | &subscription_id, | ||
| 85 | &vec![ | ||
| 86 | generate_test_key_1_metadata_event("fred"), | ||
| 87 | generate_test_key_1_relay_list_event(), | ||
| 88 | ], | ||
| 89 | )?; | ||
| 90 | Ok(()) | ||
| 91 | }), | ||
| 92 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 93 | relay.respond_events( | ||
| 94 | client_id, | ||
| 95 | &subscription_id, | ||
| 96 | &vec![ | ||
| 97 | generate_test_key_1_metadata_event("fred"), | ||
| 98 | generate_test_key_1_relay_list_event(), | ||
| 99 | ], | ||
| 100 | )?; | ||
| 101 | Ok(()) | ||
| 102 | }), | ||
| 103 | )) | ||
| 104 | } | ||
| 105 | 80 | ||
| 106 | #[test] | 81 | #[test] |
| 107 | #[serial] | 82 | #[serial] |
| 108 | fn when_latest_metadata_and_relay_list_on_some_relays_but_others_have_none() | 83 | fn when_latest_metadata_and_relay_list_on_all_relays() -> Result<()> { |
| 109 | -> Result<()> { | 84 | futures::executor::block_on(run_test_displays_correct_name( |
| 110 | futures::executor::block_on(run_test_displays_correct_name( | 85 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 111 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 86 | relay.respond_events( |
| 112 | relay.respond_events( | 87 | client_id, |
| 113 | client_id, | 88 | &subscription_id, |
| 114 | &subscription_id, | 89 | &vec![ |
| 115 | &vec![ | 90 | generate_test_key_1_metadata_event("fred"), |
| 116 | generate_test_key_1_metadata_event("fred"), | 91 | generate_test_key_1_relay_list_event_same_as_fallback(), |
| 117 | generate_test_key_1_relay_list_event(), | 92 | ], |
| 118 | ], | 93 | )?; |
| 119 | )?; | 94 | Ok(()) |
| 120 | Ok(()) | 95 | }), |
| 121 | }), | 96 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 122 | None, | 97 | relay.respond_events( |
| 123 | )) | 98 | client_id, |
| 124 | } | 99 | &subscription_id, |
| 100 | &vec![ | ||
| 101 | generate_test_key_1_metadata_event("fred"), | ||
| 102 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 103 | ], | ||
| 104 | )?; | ||
| 105 | Ok(()) | ||
| 106 | }), | ||
| 107 | )) | ||
| 108 | } | ||
| 125 | 109 | ||
| 126 | #[test] | 110 | #[test] |
| 127 | #[serial] | 111 | #[serial] |
| 128 | fn when_latest_metadata_only_on_relay_and_relay_list_on_another() -> Result<()> { | 112 | fn when_latest_metadata_and_relay_list_on_some_relays_but_others_have_none() |
| 129 | futures::executor::block_on(run_test_displays_correct_name( | 113 | -> Result<()> { |
| 130 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 114 | futures::executor::block_on(run_test_displays_correct_name( |
| 131 | relay.respond_events( | 115 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 132 | client_id, | 116 | relay.respond_events( |
| 133 | &subscription_id, | 117 | client_id, |
| 134 | &vec![generate_test_key_1_metadata_event("fred")], | 118 | &subscription_id, |
| 135 | )?; | 119 | &vec![ |
| 136 | Ok(()) | 120 | generate_test_key_1_metadata_event("fred"), |
| 137 | }), | 121 | generate_test_key_1_relay_list_event_same_as_fallback(), |
| 138 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 122 | ], |
| 139 | relay.respond_events( | 123 | )?; |
| 140 | client_id, | 124 | Ok(()) |
| 141 | &subscription_id, | 125 | }), |
| 142 | &vec![generate_test_key_1_relay_list_event()], | 126 | None, |
| 143 | )?; | 127 | )) |
| 144 | Ok(()) | 128 | } |
| 145 | }), | ||
| 146 | )) | ||
| 147 | } | ||
| 148 | 129 | ||
| 149 | #[test] | 130 | #[test] |
| 150 | #[serial] | 131 | #[serial] |
| 151 | fn when_some_relays_return_old_metadata_event() -> Result<()> { | 132 | fn when_latest_metadata_only_on_relay_and_relay_list_on_another() -> Result<()> { |
| 152 | futures::executor::block_on(run_test_displays_correct_name( | 133 | futures::executor::block_on(run_test_displays_correct_name( |
| 153 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 134 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 154 | relay.respond_events( | 135 | relay.respond_events( |
| 155 | client_id, | 136 | client_id, |
| 156 | &subscription_id, | 137 | &subscription_id, |
| 157 | &vec![ | 138 | &vec![generate_test_key_1_metadata_event("fred")], |
| 158 | generate_test_key_1_metadata_event("fred"), | 139 | )?; |
| 159 | generate_test_key_1_relay_list_event(), | 140 | Ok(()) |
| 160 | ], | 141 | }), |
| 161 | )?; | 142 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 162 | Ok(()) | 143 | relay.respond_events( |
| 163 | }), | 144 | client_id, |
| 164 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 145 | &subscription_id, |
| 165 | relay.respond_events( | 146 | &vec![generate_test_key_1_relay_list_event_same_as_fallback()], |
| 166 | client_id, | 147 | )?; |
| 167 | &subscription_id, | 148 | Ok(()) |
| 168 | &vec![generate_test_key_1_metadata_event_old("fred old")], | 149 | }), |
| 169 | )?; | 150 | )) |
| 170 | Ok(()) | 151 | } |
| 171 | }), | ||
| 172 | )) | ||
| 173 | } | ||
| 174 | 152 | ||
| 175 | #[test] | 153 | #[test] |
| 176 | #[serial] | 154 | #[serial] |
| 177 | fn when_some_relays_return_other_users_metadata() -> Result<()> { | 155 | fn when_some_relays_return_old_metadata_event() -> Result<()> { |
| 178 | futures::executor::block_on(run_test_displays_correct_name( | 156 | futures::executor::block_on(run_test_displays_correct_name( |
| 179 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 157 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 180 | relay.respond_events( | 158 | relay.respond_events( |
| 181 | client_id, | 159 | client_id, |
| 182 | &subscription_id, | 160 | &subscription_id, |
| 183 | &vec![generate_test_key_2_metadata_event("carole")], | 161 | &vec![ |
| 184 | )?; | 162 | generate_test_key_1_metadata_event("fred"), |
| 185 | Ok(()) | 163 | generate_test_key_1_relay_list_event_same_as_fallback(), |
| 186 | }), | 164 | ], |
| 187 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 165 | )?; |
| 188 | relay.respond_events( | 166 | Ok(()) |
| 189 | client_id, | 167 | }), |
| 190 | &subscription_id, | 168 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 191 | &vec![ | 169 | relay.respond_events( |
| 192 | generate_test_key_1_metadata_event_old("fred"), | 170 | client_id, |
| 193 | generate_test_key_1_relay_list_event(), | 171 | &subscription_id, |
| 194 | ], | 172 | &vec![generate_test_key_1_metadata_event_old("fred old")], |
| 195 | )?; | 173 | )?; |
| 196 | Ok(()) | 174 | Ok(()) |
| 197 | }), | 175 | }), |
| 198 | )) | 176 | )) |
| 199 | } | 177 | } |
| 200 | 178 | ||
| 201 | #[test] | 179 | #[test] |
| 202 | #[serial] | 180 | #[serial] |
| 203 | fn when_some_relays_return_other_event_kinds() -> Result<()> { | 181 | fn when_some_relays_return_other_users_metadata() -> Result<()> { |
| 204 | futures::executor::block_on(run_test_displays_correct_name( | 182 | futures::executor::block_on(run_test_displays_correct_name( |
| 205 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 183 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 206 | let mut event = generate_test_key_1_metadata_event("Fred"); | 184 | relay.respond_events( |
| 207 | event.kind = nostr::Kind::TextNote; | 185 | client_id, |
| 208 | relay.respond_events( | 186 | &subscription_id, |
| 209 | client_id, | 187 | &vec![generate_test_key_2_metadata_event("carole")], |
| 210 | &subscription_id, | 188 | )?; |
| 211 | &vec![make_event_old_or_change_user(event, &TEST_KEY_1_KEYS, 0)], | 189 | Ok(()) |
| 212 | )?; | 190 | }), |
| 191 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 192 | relay.respond_events( | ||
| 193 | client_id, | ||
| 194 | &subscription_id, | ||
| 195 | &vec![ | ||
| 196 | generate_test_key_1_metadata_event_old("fred"), | ||
| 197 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 198 | ], | ||
| 199 | )?; | ||
| 200 | Ok(()) | ||
| 201 | }), | ||
| 202 | )) | ||
| 203 | } | ||
| 204 | |||
| 205 | #[test] | ||
| 206 | #[serial] | ||
| 207 | fn when_some_relays_return_other_event_kinds() -> Result<()> { | ||
| 208 | futures::executor::block_on(run_test_displays_correct_name( | ||
| 209 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 210 | let mut event = generate_test_key_1_metadata_event("Fred"); | ||
| 211 | event.kind = nostr::Kind::TextNote; | ||
| 212 | relay.respond_events( | ||
| 213 | client_id, | ||
| 214 | &subscription_id, | ||
| 215 | &vec![make_event_old_or_change_user(event, &TEST_KEY_1_KEYS, 0)], | ||
| 216 | )?; | ||
| 217 | Ok(()) | ||
| 218 | }), | ||
| 219 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 220 | relay.respond_events( | ||
| 221 | client_id, | ||
| 222 | &subscription_id, | ||
| 223 | &vec![ | ||
| 224 | generate_test_key_1_metadata_event_old("fred"), | ||
| 225 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 226 | ], | ||
| 227 | )?; | ||
| 228 | Ok(()) | ||
| 229 | }), | ||
| 230 | )) | ||
| 231 | } | ||
| 232 | |||
| 233 | mod when_specifying_command_line_nsec_only { | ||
| 234 | use super::*; | ||
| 235 | |||
| 236 | #[test] | ||
| 237 | #[serial] | ||
| 238 | fn displays_correct_name() -> Result<()> { | ||
| 239 | futures::executor::block_on( | ||
| 240 | run_test_when_specifying_command_line_nsec_only_displays_correct_name( | ||
| 241 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 242 | relay.respond_events( | ||
| 243 | client_id, | ||
| 244 | &subscription_id, | ||
| 245 | &vec![ | ||
| 246 | generate_test_key_1_metadata_event("fred"), | ||
| 247 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 248 | ], | ||
| 249 | )?; | ||
| 250 | Ok(()) | ||
| 251 | }), | ||
| 252 | None, | ||
| 253 | ), | ||
| 254 | ) | ||
| 255 | } | ||
| 256 | async fn run_test_when_specifying_command_line_nsec_only_displays_correct_name( | ||
| 257 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 258 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 259 | ) -> Result<()> { | ||
| 260 | let (mut r51, mut r52) = ( | ||
| 261 | Relay::new(8051, None, relay_listener1), | ||
| 262 | Relay::new(8052, None, relay_listener2), | ||
| 263 | ); | ||
| 264 | |||
| 265 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 266 | with_fresh_config(|| { | ||
| 267 | let mut p = CliTester::new(["login", "--nsec", TEST_KEY_1_NSEC]); | ||
| 268 | |||
| 269 | p.expect("searching for your details...\r\n")?; | ||
| 270 | p.expect("\r")?; | ||
| 271 | |||
| 272 | p.expect_end_with("logged in as fred\r\n")?; | ||
| 273 | for p in [51, 52] { | ||
| 274 | shutdown_relay(8000 + p)?; | ||
| 275 | } | ||
| 276 | Ok(()) | ||
| 277 | }) | ||
| 278 | }); | ||
| 279 | |||
| 280 | // launch relay | ||
| 281 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 282 | |||
| 283 | cli_tester_handle.join().unwrap()?; | ||
| 213 | Ok(()) | 284 | Ok(()) |
| 214 | }), | 285 | } |
| 215 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 286 | } |
| 216 | relay.respond_events( | 287 | mod when_specifying_command_line_password_only { |
| 217 | client_id, | 288 | use super::*; |
| 218 | &subscription_id, | 289 | |
| 219 | &vec![ | 290 | #[test] |
| 220 | generate_test_key_1_metadata_event_old("fred"), | 291 | #[serial] |
| 221 | generate_test_key_1_relay_list_event(), | 292 | fn displays_correct_name() -> Result<()> { |
| 222 | ], | 293 | futures::executor::block_on( |
| 223 | )?; | 294 | run_test_when_specifying_command_line_password_only_displays_correct_name( |
| 295 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 296 | relay.respond_events( | ||
| 297 | client_id, | ||
| 298 | &subscription_id, | ||
| 299 | &vec![ | ||
| 300 | generate_test_key_1_metadata_event("fred"), | ||
| 301 | generate_test_key_1_relay_list_event_same_as_fallback(), | ||
| 302 | ], | ||
| 303 | )?; | ||
| 304 | Ok(()) | ||
| 305 | }), | ||
| 306 | None, | ||
| 307 | ), | ||
| 308 | ) | ||
| 309 | } | ||
| 310 | async fn run_test_when_specifying_command_line_password_only_displays_correct_name( | ||
| 311 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 312 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 313 | ) -> Result<()> { | ||
| 314 | let (mut r51, mut r52) = ( | ||
| 315 | Relay::new(8051, None, relay_listener1), | ||
| 316 | Relay::new(8052, None, relay_listener2), | ||
| 317 | ); | ||
| 318 | |||
| 319 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 320 | with_fresh_config(|| { | ||
| 321 | CliTester::new([ | ||
| 322 | "login", | ||
| 323 | "--offline", | ||
| 324 | "--nsec", | ||
| 325 | TEST_KEY_1_NSEC, | ||
| 326 | "--password", | ||
| 327 | TEST_PASSWORD, | ||
| 328 | ]) | ||
| 329 | .expect_end_eventually()?; | ||
| 330 | |||
| 331 | let mut p = CliTester::new(["login", "--password", TEST_PASSWORD]); | ||
| 332 | |||
| 333 | p.expect("searching for your details...\r\n")?; | ||
| 334 | p.expect("\r")?; | ||
| 335 | |||
| 336 | p.expect_end_with("logged in as fred\r\n")?; | ||
| 337 | for p in [51, 52] { | ||
| 338 | shutdown_relay(8000 + p)?; | ||
| 339 | } | ||
| 340 | Ok(()) | ||
| 341 | }) | ||
| 342 | }); | ||
| 343 | |||
| 344 | // launch relay | ||
| 345 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 346 | |||
| 347 | cli_tester_handle.join().unwrap()?; | ||
| 224 | Ok(()) | 348 | Ok(()) |
| 225 | }), | 349 | } |
| 226 | )) | 350 | } |
| 227 | } | ||
| 228 | 351 | ||
| 229 | mod when_specifying_command_line_nsec_only { | 352 | mod when_specifying_command_line_nsec_and_password { |
| 230 | use super::*; | 353 | use super::*; |
| 231 | 354 | ||
| 232 | #[test] | 355 | #[test] |
| 233 | #[serial] | 356 | #[serial] |
| 234 | fn displays_correct_name() -> Result<()> { | 357 | fn displays_correct_name() -> Result<()> { |
| 235 | futures::executor::block_on( | 358 | futures::executor::block_on( |
| 236 | run_test_when_specifying_command_line_nsec_only_displays_correct_name( | 359 | run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( |
| 237 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 360 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 238 | relay.respond_events( | 361 | relay.respond_events( |
| 239 | client_id, | 362 | client_id, |
| 240 | &subscription_id, | 363 | &subscription_id, |
| 241 | &vec![ | 364 | &vec![ |
| 242 | generate_test_key_1_metadata_event("fred"), | 365 | generate_test_key_1_metadata_event("fred"), |
| 243 | generate_test_key_1_relay_list_event(), | 366 | generate_test_key_1_relay_list_event_same_as_fallback(), |
| 244 | ], | 367 | ], |
| 245 | )?; | 368 | )?; |
| 246 | Ok(()) | 369 | Ok(()) |
| @@ -248,8 +371,58 @@ mod with_relays { | |||
| 248 | None, | 371 | None, |
| 249 | ), | 372 | ), |
| 250 | ) | 373 | ) |
| 374 | } | ||
| 375 | async fn run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( | ||
| 376 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 377 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 378 | ) -> Result<()> { | ||
| 379 | let (mut r51, mut r52) = ( | ||
| 380 | Relay::new(8051, None, relay_listener1), | ||
| 381 | Relay::new(8052, None, relay_listener2), | ||
| 382 | ); | ||
| 383 | |||
| 384 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 385 | with_fresh_config(|| { | ||
| 386 | let mut p = CliTester::new([ | ||
| 387 | "login", | ||
| 388 | "--nsec", | ||
| 389 | TEST_KEY_1_NSEC, | ||
| 390 | "--password", | ||
| 391 | TEST_PASSWORD, | ||
| 392 | ]); | ||
| 393 | |||
| 394 | p.expect("searching for your details...\r\n")?; | ||
| 395 | p.expect("\r")?; | ||
| 396 | |||
| 397 | p.expect_end_with("logged in as fred\r\n")?; | ||
| 398 | for p in [51, 52] { | ||
| 399 | shutdown_relay(8000 + p)?; | ||
| 400 | } | ||
| 401 | Ok(()) | ||
| 402 | }) | ||
| 403 | }); | ||
| 404 | |||
| 405 | // launch relay | ||
| 406 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 407 | |||
| 408 | cli_tester_handle.join().unwrap()?; | ||
| 409 | Ok(()) | ||
| 410 | } | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | mod when_no_metadata_found { | ||
| 415 | use super::*; | ||
| 416 | |||
| 417 | #[test] | ||
| 418 | #[serial] | ||
| 419 | fn warm_user_and_displays_npub() -> Result<()> { | ||
| 420 | futures::executor::block_on( | ||
| 421 | run_test_when_no_metadata_found_warns_user_and_uses_npub(None, None), | ||
| 422 | ) | ||
| 251 | } | 423 | } |
| 252 | async fn run_test_when_specifying_command_line_nsec_only_displays_correct_name( | 424 | |
| 425 | async fn run_test_when_no_metadata_found_warns_user_and_uses_npub( | ||
| 253 | relay_listener1: Option<ListenerReqFunc<'_>>, | 426 | relay_listener1: Option<ListenerReqFunc<'_>>, |
| 254 | relay_listener2: Option<ListenerReqFunc<'_>>, | 427 | relay_listener2: Option<ListenerReqFunc<'_>>, |
| 255 | ) -> Result<()> { | 428 | ) -> Result<()> { |
| @@ -260,12 +433,24 @@ mod with_relays { | |||
| 260 | 433 | ||
| 261 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 434 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 262 | with_fresh_config(|| { | 435 | with_fresh_config(|| { |
| 263 | let mut p = CliTester::new(["login", "--nsec", TEST_KEY_1_NSEC]); | 436 | let mut p = CliTester::new(["login"]); |
| 437 | |||
| 438 | p.expect_input(EXPECTED_NSEC_PROMPT)? | ||
| 439 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 440 | |||
| 441 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 442 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 443 | .succeeds_with(TEST_PASSWORD)?; | ||
| 264 | 444 | ||
| 265 | p.expect("searching for your details...\r\n")?; | 445 | p.expect("searching for your details...\r\n")?; |
| 266 | p.expect("\r")?; | 446 | p.expect("\r")?; |
| 447 | p.expect( | ||
| 448 | "cannot find your account metadata (name, etc) on relays\r\n", | ||
| 449 | )?; | ||
| 267 | 450 | ||
| 268 | p.expect_end_with("logged in as fred\r\n")?; | 451 | p.expect_end_with( |
| 452 | format!("logged in as {TEST_KEY_1_NPUB}\r\n").as_str(), | ||
| 453 | )?; | ||
| 269 | for p in [51, 52] { | 454 | for p in [51, 52] { |
| 270 | shutdown_relay(8000 + p)?; | 455 | shutdown_relay(8000 + p)?; |
| 271 | } | 456 | } |
| @@ -280,22 +465,20 @@ mod with_relays { | |||
| 280 | Ok(()) | 465 | Ok(()) |
| 281 | } | 466 | } |
| 282 | } | 467 | } |
| 283 | mod when_specifying_command_line_password_only { | 468 | |
| 469 | mod when_metadata_but_no_relay_list_found { | ||
| 284 | use super::*; | 470 | use super::*; |
| 285 | 471 | ||
| 286 | #[test] | 472 | #[test] |
| 287 | #[serial] | 473 | #[serial] |
| 288 | fn displays_correct_name() -> Result<()> { | 474 | fn warm_user_and_displays_name() -> Result<()> { |
| 289 | futures::executor::block_on( | 475 | futures::executor::block_on( |
| 290 | run_test_when_specifying_command_line_password_only_displays_correct_name( | 476 | run_test_when_no_relay_list_found_warns_user_and_uses_npub( |
| 291 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 477 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 292 | relay.respond_events( | 478 | relay.respond_events( |
| 293 | client_id, | 479 | client_id, |
| 294 | &subscription_id, | 480 | &subscription_id, |
| 295 | &vec![ | 481 | &vec![generate_test_key_1_metadata_event("fred")], |
| 296 | generate_test_key_1_metadata_event("fred"), | ||
| 297 | generate_test_key_1_relay_list_event(), | ||
| 298 | ], | ||
| 299 | )?; | 482 | )?; |
| 300 | Ok(()) | 483 | Ok(()) |
| 301 | }), | 484 | }), |
| @@ -303,7 +486,8 @@ mod with_relays { | |||
| 303 | ), | 486 | ), |
| 304 | ) | 487 | ) |
| 305 | } | 488 | } |
| 306 | async fn run_test_when_specifying_command_line_password_only_displays_correct_name( | 489 | |
| 490 | async fn run_test_when_no_relay_list_found_warns_user_and_uses_npub( | ||
| 307 | relay_listener1: Option<ListenerReqFunc<'_>>, | 491 | relay_listener1: Option<ListenerReqFunc<'_>>, |
| 308 | relay_listener2: Option<ListenerReqFunc<'_>>, | 492 | relay_listener2: Option<ListenerReqFunc<'_>>, |
| 309 | ) -> Result<()> { | 493 | ) -> Result<()> { |
| @@ -314,20 +498,18 @@ mod with_relays { | |||
| 314 | 498 | ||
| 315 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 499 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 316 | with_fresh_config(|| { | 500 | with_fresh_config(|| { |
| 317 | CliTester::new([ | 501 | let mut p = CliTester::new(["login"]); |
| 318 | "login", | ||
| 319 | "--offline", | ||
| 320 | "--nsec", | ||
| 321 | TEST_KEY_1_NSEC, | ||
| 322 | "--password", | ||
| 323 | TEST_PASSWORD, | ||
| 324 | ]) | ||
| 325 | .expect_end_eventually()?; | ||
| 326 | 502 | ||
| 327 | let mut p = CliTester::new(["login", "--password", TEST_PASSWORD]); | 503 | p.expect_input(EXPECTED_NSEC_PROMPT)? |
| 504 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 505 | |||
| 506 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 507 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 508 | .succeeds_with(TEST_PASSWORD)?; | ||
| 328 | 509 | ||
| 329 | p.expect("searching for your details...\r\n")?; | 510 | p.expect("searching for your details...\r\n")?; |
| 330 | p.expect("\r")?; | 511 | p.expect("\r")?; |
| 512 | p.expect("cannot find your relay list. consider using another nostr client to create one to enhance your nostr experience.\r\n")?; | ||
| 331 | 513 | ||
| 332 | p.expect_end_with("logged in as fred\r\n")?; | 514 | p.expect_end_with("logged in as fred\r\n")?; |
| 333 | for p in [51, 52] { | 515 | for p in [51, 52] { |
| @@ -344,37 +526,42 @@ mod with_relays { | |||
| 344 | Ok(()) | 526 | Ok(()) |
| 345 | } | 527 | } |
| 346 | } | 528 | } |
| 529 | } | ||
| 530 | |||
| 531 | mod when_second_time_login_and_details_already_fetched { | ||
| 532 | use super::*; | ||
| 533 | |||
| 534 | // TODO: the following two tests would require a fake config file or | ||
| 535 | // fake time | ||
| 536 | // - uses_relays_from_user_relay_list | ||
| 537 | // - dislays_correct_name - when_local_metadata_is_the_most_recent | ||
| 347 | 538 | ||
| 348 | mod when_specifying_command_line_nsec_and_password { | 539 | mod uses_cache { |
| 349 | use super::*; | 540 | use super::*; |
| 350 | 541 | ||
| 351 | #[test] | 542 | #[test] |
| 352 | #[serial] | 543 | #[serial] |
| 353 | fn displays_correct_name() -> Result<()> { | 544 | fn dislays_logged_in_with_correct_name() -> Result<()> { |
| 354 | futures::executor::block_on( | 545 | futures::executor::block_on(run_test_dislays_logged_in_with_correct_name(Some( |
| 355 | run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( | 546 | &|relay, client_id, subscription_id, _| -> Result<()> { |
| 356 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | 547 | relay.respond_events( |
| 357 | relay.respond_events( | 548 | client_id, |
| 358 | client_id, | 549 | &subscription_id, |
| 359 | &subscription_id, | 550 | &vec![ |
| 360 | &vec![ | 551 | generate_test_key_1_metadata_event("fred"), |
| 361 | generate_test_key_1_metadata_event("fred"), | 552 | generate_test_key_1_relay_list_event_same_as_fallback(), |
| 362 | generate_test_key_1_relay_list_event(), | 553 | ], |
| 363 | ], | 554 | )?; |
| 364 | )?; | 555 | Ok(()) |
| 365 | Ok(()) | 556 | }, |
| 366 | }), | 557 | ))) |
| 367 | None, | ||
| 368 | ), | ||
| 369 | ) | ||
| 370 | } | 558 | } |
| 371 | async fn run_test_when_specifying_command_line_nsec_and_password_displays_correct_name( | 559 | async fn run_test_dislays_logged_in_with_correct_name( |
| 372 | relay_listener1: Option<ListenerReqFunc<'_>>, | 560 | relay_listener: Option<ListenerReqFunc<'_>>, |
| 373 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 374 | ) -> Result<()> { | 561 | ) -> Result<()> { |
| 375 | let (mut r51, mut r52) = ( | 562 | let (mut r51, mut r52) = ( |
| 376 | Relay::new(8051, None, relay_listener1), | 563 | Relay::new(8051, None, relay_listener), |
| 377 | Relay::new(8052, None, relay_listener2), | 564 | Relay::new(8052, None, None), |
| 378 | ); | 565 | ); |
| 379 | 566 | ||
| 380 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 567 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| @@ -387,13 +574,19 @@ mod with_relays { | |||
| 387 | TEST_PASSWORD, | 574 | TEST_PASSWORD, |
| 388 | ]); | 575 | ]); |
| 389 | 576 | ||
| 390 | p.expect("searching for your details...\r\n")?; | 577 | p.expect_end_eventually_with("logged in as fred\r\n")?; |
| 391 | p.expect("\r")?; | ||
| 392 | 578 | ||
| 393 | p.expect_end_with("logged in as fred\r\n")?; | ||
| 394 | for p in [51, 52] { | 579 | for p in [51, 52] { |
| 395 | shutdown_relay(8000 + p)?; | 580 | shutdown_relay(8000 + p)?; |
| 396 | } | 581 | } |
| 582 | |||
| 583 | let mut p = CliTester::new(["login", "--password", TEST_PASSWORD]); | ||
| 584 | |||
| 585 | p.expect("searching for your details...\r\n")?; | ||
| 586 | p.expect("\r")?; | ||
| 587 | |||
| 588 | p.expect_end_eventually_with("logged in as fred\r\n")?; | ||
| 589 | |||
| 397 | Ok(()) | 590 | Ok(()) |
| 398 | }) | 591 | }) |
| 399 | }); | 592 | }); |
| @@ -402,90 +595,25 @@ mod with_relays { | |||
| 402 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | 595 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); |
| 403 | 596 | ||
| 404 | cli_tester_handle.join().unwrap()?; | 597 | cli_tester_handle.join().unwrap()?; |
| 598 | |||
| 405 | Ok(()) | 599 | Ok(()) |
| 406 | } | 600 | } |
| 407 | } | 601 | } |
| 408 | } | 602 | } |
| 409 | 603 | } | |
| 410 | mod when_no_metadata_found { | 604 | mod when_user_relay_list_contains_write_relays_not_in_fallback_list { |
| 411 | use super::*; | 605 | use super::*; |
| 412 | 606 | mod when_latest_metadata_not_on_fallback_relays_only_on_relays_in_user_list { | |
| 413 | #[test] | ||
| 414 | #[serial] | ||
| 415 | fn warm_user_and_displays_npub() -> Result<()> { | ||
| 416 | futures::executor::block_on( | ||
| 417 | run_test_when_no_metadata_found_warns_user_and_uses_npub(None, None), | ||
| 418 | ) | ||
| 419 | } | ||
| 420 | |||
| 421 | async fn run_test_when_no_metadata_found_warns_user_and_uses_npub( | ||
| 422 | relay_listener1: Option<ListenerReqFunc<'_>>, | ||
| 423 | relay_listener2: Option<ListenerReqFunc<'_>>, | ||
| 424 | ) -> Result<()> { | ||
| 425 | let (mut r51, mut r52) = ( | ||
| 426 | Relay::new(8051, None, relay_listener1), | ||
| 427 | Relay::new(8052, None, relay_listener2), | ||
| 428 | ); | ||
| 429 | |||
| 430 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 431 | with_fresh_config(|| { | ||
| 432 | let mut p = CliTester::new(["login"]); | ||
| 433 | |||
| 434 | p.expect_input(EXPECTED_NSEC_PROMPT)? | ||
| 435 | .succeeds_with(TEST_KEY_1_NSEC)?; | ||
| 436 | |||
| 437 | p.expect_password(EXPECTED_SET_PASSWORD_PROMPT)? | ||
| 438 | .with_confirmation(EXPECTED_SET_PASSWORD_CONFIRM_PROMPT)? | ||
| 439 | .succeeds_with(TEST_PASSWORD)?; | ||
| 440 | |||
| 441 | p.expect("searching for your details...\r\n")?; | ||
| 442 | p.expect("\r")?; | ||
| 443 | p.expect("cannot find your account metadata (name, etc) on relays\r\n")?; | ||
| 444 | |||
| 445 | p.expect_end_with(format!("logged in as {TEST_KEY_1_NPUB}\r\n").as_str())?; | ||
| 446 | for p in [51, 52] { | ||
| 447 | shutdown_relay(8000 + p)?; | ||
| 448 | } | ||
| 449 | Ok(()) | ||
| 450 | }) | ||
| 451 | }); | ||
| 452 | |||
| 453 | // launch relay | ||
| 454 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 455 | |||
| 456 | cli_tester_handle.join().unwrap()?; | ||
| 457 | Ok(()) | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | mod when_metadata_but_no_relay_list_found { | ||
| 462 | use super::*; | 607 | use super::*; |
| 463 | 608 | async fn run_test_displays_correct_name( | |
| 464 | #[test] | ||
| 465 | #[serial] | ||
| 466 | fn warm_user_and_displays_name() -> Result<()> { | ||
| 467 | futures::executor::block_on( | ||
| 468 | run_test_when_no_relay_list_found_warns_user_and_uses_npub( | ||
| 469 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 470 | relay.respond_events( | ||
| 471 | client_id, | ||
| 472 | &subscription_id, | ||
| 473 | &vec![generate_test_key_1_metadata_event("fred")], | ||
| 474 | )?; | ||
| 475 | Ok(()) | ||
| 476 | }), | ||
| 477 | None, | ||
| 478 | ), | ||
| 479 | ) | ||
| 480 | } | ||
| 481 | |||
| 482 | async fn run_test_when_no_relay_list_found_warns_user_and_uses_npub( | ||
| 483 | relay_listener1: Option<ListenerReqFunc<'_>>, | 609 | relay_listener1: Option<ListenerReqFunc<'_>>, |
| 484 | relay_listener2: Option<ListenerReqFunc<'_>>, | 610 | relay_listener2: Option<ListenerReqFunc<'_>>, |
| 485 | ) -> Result<()> { | 611 | ) -> Result<()> { |
| 486 | let (mut r51, mut r52) = ( | 612 | let (mut r51, mut r52, mut r53, mut r55) = ( |
| 487 | Relay::new(8051, None, relay_listener1), | 613 | Relay::new(8051, None, relay_listener1), |
| 488 | Relay::new(8052, None, relay_listener2), | 614 | Relay::new(8052, None, None), |
| 615 | Relay::new(8053, None, relay_listener2), | ||
| 616 | Relay::new(8055, None, None), | ||
| 489 | ); | 617 | ); |
| 490 | 618 | ||
| 491 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 619 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| @@ -501,10 +629,9 @@ mod with_relays { | |||
| 501 | 629 | ||
| 502 | p.expect("searching for your details...\r\n")?; | 630 | p.expect("searching for your details...\r\n")?; |
| 503 | p.expect("\r")?; | 631 | p.expect("\r")?; |
| 504 | p.expect("cannot find your relay list. consider using another nostr client to create one to enhance your nostr experience.\r\n")?; | ||
| 505 | 632 | ||
| 506 | p.expect_end_with("logged in as fred\r\n")?; | 633 | p.expect_end_with("logged in as fred\r\n")?; |
| 507 | for p in [51, 52] { | 634 | for p in [51, 52, 53, 55] { |
| 508 | shutdown_relay(8000 + p)?; | 635 | shutdown_relay(8000 + p)?; |
| 509 | } | 636 | } |
| 510 | Ok(()) | 637 | Ok(()) |
| @@ -512,83 +639,45 @@ mod with_relays { | |||
| 512 | }); | 639 | }); |
| 513 | 640 | ||
| 514 | // launch relay | 641 | // launch relay |
| 515 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | 642 | let _ = join!( |
| 643 | r51.listen_until_close(), | ||
| 644 | r52.listen_until_close(), | ||
| 645 | r53.listen_until_close(), | ||
| 646 | r55.listen_until_close(), | ||
| 647 | ); | ||
| 516 | 648 | ||
| 517 | cli_tester_handle.join().unwrap()?; | 649 | cli_tester_handle.join().unwrap()?; |
| 518 | Ok(()) | 650 | Ok(()) |
| 519 | } | 651 | } |
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | mod when_second_time_login_and_details_already_fetched { | ||
| 524 | use super::*; | ||
| 525 | |||
| 526 | // TODO: the following two tests would require a fake config file or | ||
| 527 | // fake time | ||
| 528 | // - uses_relays_from_user_relay_list | ||
| 529 | // - dislays_correct_name - when_local_metadata_is_the_most_recent | ||
| 530 | |||
| 531 | mod uses_cache { | ||
| 532 | use super::*; | ||
| 533 | 652 | ||
| 653 | /// this also tests that additional relays are queried | ||
| 534 | #[test] | 654 | #[test] |
| 535 | #[serial] | 655 | #[serial] |
| 536 | fn dislays_logged_in_with_correct_name() -> Result<()> { | 656 | fn displays_correct_name() -> Result<()> { |
| 537 | futures::executor::block_on(run_test_dislays_logged_in_with_correct_name(Some( | 657 | futures::executor::block_on(run_test_displays_correct_name( |
| 538 | &|relay, client_id, subscription_id, _| -> Result<()> { | 658 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 539 | relay.respond_events( | 659 | relay.respond_events( |
| 540 | client_id, | 660 | client_id, |
| 541 | &subscription_id, | 661 | &subscription_id, |
| 542 | &vec![ | 662 | &vec![ |
| 543 | generate_test_key_1_metadata_event("fred"), | 663 | generate_test_key_1_metadata_event_old("Fred"), |
| 544 | generate_test_key_1_relay_list_event(), | 664 | generate_test_key_1_relay_list_event(), |
| 545 | ], | 665 | ], |
| 546 | )?; | 666 | )?; |
| 547 | Ok(()) | 667 | Ok(()) |
| 548 | }, | 668 | }), |
| 549 | ))) | 669 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { |
| 550 | } | 670 | relay.respond_events( |
| 551 | async fn run_test_dislays_logged_in_with_correct_name( | 671 | client_id, |
| 552 | relay_listener: Option<ListenerReqFunc<'_>>, | 672 | &subscription_id, |
| 553 | ) -> Result<()> { | 673 | &vec![ |
| 554 | let (mut r51, mut r52) = ( | 674 | generate_test_key_1_metadata_event("fred"), |
| 555 | Relay::new(8051, None, relay_listener), | 675 | generate_test_key_1_relay_list_event(), |
| 556 | Relay::new(8052, None, None), | 676 | ], |
| 557 | ); | 677 | )?; |
| 558 | |||
| 559 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 560 | with_fresh_config(|| { | ||
| 561 | let mut p = CliTester::new([ | ||
| 562 | "login", | ||
| 563 | "--nsec", | ||
| 564 | TEST_KEY_1_NSEC, | ||
| 565 | "--password", | ||
| 566 | TEST_PASSWORD, | ||
| 567 | ]); | ||
| 568 | |||
| 569 | p.expect_end_eventually_with("logged in as fred\r\n")?; | ||
| 570 | |||
| 571 | for p in [51, 52] { | ||
| 572 | shutdown_relay(8000 + p)?; | ||
| 573 | } | ||
| 574 | |||
| 575 | let mut p = CliTester::new(["login", "--password", TEST_PASSWORD]); | ||
| 576 | |||
| 577 | p.expect("searching for your details...\r\n")?; | ||
| 578 | p.expect("\r")?; | ||
| 579 | |||
| 580 | p.expect_end_eventually_with("logged in as fred\r\n")?; | ||
| 581 | |||
| 582 | Ok(()) | 678 | Ok(()) |
| 583 | }) | 679 | }), |
| 584 | }); | 680 | )) |
| 585 | |||
| 586 | // launch relay | ||
| 587 | let _ = join!(r51.listen_until_close(), r52.listen_until_close(),); | ||
| 588 | |||
| 589 | cli_tester_handle.join().unwrap()?; | ||
| 590 | |||
| 591 | Ok(()) | ||
| 592 | } | 681 | } |
| 593 | } | 682 | } |
| 594 | } | 683 | } |