upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client.rs31
-rw-r--r--src/key_handling/users.rs320
-rw-r--r--test_utils/src/lib.rs19
-rw-r--r--tests/login.rs831
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
112async 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)]
120pub struct Params { 131pub 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
136fn get_dedup_events( 147fn 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
59pub 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
59pub static TEST_KEY_2_NSEC: &str = 78pub static TEST_KEY_2_NSEC: &str =
60 "nsec1ypglg6nj6ep0g2qmyfqcv2al502gje3jvpwye6mthmkvj93tqkesknv6qm"; 79 "nsec1ypglg6nj6ep0g2qmyfqcv2al502gje3jvpwye6mthmkvj93tqkesknv6qm";
61pub static TEST_KEY_2_NPUB: &str = 80pub 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 }