1- use crate :: integration_tests :: core :: * ;
2- use crate :: WhitenoiseError ;
1+ use std :: time :: Duration ;
2+
33use async_trait:: async_trait;
44use nostr_sdk:: prelude:: * ;
5- use std:: time:: Duration ;
5+
6+ use crate :: integration_tests:: core:: * ;
7+ use crate :: WhitenoiseError ;
68
79pub struct VerifyLastSyncedTimestampTestCase {
810 mode : Mode ,
@@ -31,8 +33,8 @@ impl VerifyLastSyncedTimestampTestCase {
3133 context : & ScenarioContext ,
3234 pubkey : PublicKey ,
3335 ) -> Result < Option < chrono:: DateTime < chrono:: Utc > > , WhitenoiseError > {
34- let fresh = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
35- Ok ( fresh . last_synced_at )
36+ let account = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
37+ Ok ( account . last_synced_at )
3638 }
3739
3840 async fn assert_advanced (
@@ -43,13 +45,13 @@ impl VerifyLastSyncedTimestampTestCase {
4345 description : & str ,
4446 ) -> Result < ( ) , WhitenoiseError > {
4547 retry (
46- 50 ,
47- Duration :: from_millis ( 50 ) ,
48+ 100 ,
49+ Duration :: from_millis ( 75 ) ,
4850 || async {
49- let refreshed = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
50- match ( before, refreshed . last_synced_at ) {
51+ let account = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
52+ match ( before, account . last_synced_at ) {
5153 ( None , Some ( _) ) => Ok ( ( ) ) ,
52- ( Some ( b ) , Some ( a ) ) if a > b => Ok ( ( ) ) ,
54+ ( Some ( before_time ) , Some ( after_time ) ) if after_time > before_time => Ok ( ( ) ) ,
5355 _ => Err ( WhitenoiseError :: Other ( anyhow:: anyhow!(
5456 "last_synced_at not advanced yet"
5557 ) ) ) ,
@@ -71,12 +73,8 @@ impl VerifyLastSyncedTimestampTestCase {
7173 50 ,
7274 Duration :: from_millis ( 50 ) ,
7375 || async {
74- let after = context
75- . whitenoise
76- . find_account_by_pubkey ( & pubkey)
77- . await ?
78- . last_synced_at ;
79- if after == before {
76+ let account = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
77+ if account. last_synced_at == before {
8078 Ok ( ( ) )
8179 } else {
8280 Err ( WhitenoiseError :: Other ( anyhow:: anyhow!(
@@ -89,38 +87,49 @@ impl VerifyLastSyncedTimestampTestCase {
8987 . await
9088 }
9189
92- async fn publish_account_follow_event (
90+ async fn publish_account_follow_event_with_timestamp (
9391 & self ,
9492 context : & ScenarioContext ,
9593 pubkey : PublicKey ,
94+ event_timestamp : Timestamp ,
9695 ) -> Result < ( ) , WhitenoiseError > {
97- let account_owned = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
98- let nsec = context
99- . whitenoise
100- . export_account_nsec ( & account_owned)
101- . await ?;
96+ let account = context. whitenoise . find_account_by_pubkey ( & pubkey) . await ?;
97+ let nsec = context. whitenoise . export_account_nsec ( & account) . await ?;
10298 let keys = Keys :: parse ( & nsec) ?;
103- let client = create_test_client ( & context. dev_relays , keys) . await ?;
99+ let client = create_test_client ( & context. dev_relays , keys. clone ( ) ) . await ?;
104100 let contact = Keys :: generate ( ) . public_key ( ) ;
105- publish_follow_list ( & client, & [ contact] ) . await ?;
101+
102+ let tags = vec ! [ Tag :: custom( TagKind :: p( ) , [ contact. to_hex( ) ] ) ] ;
103+ let event = EventBuilder :: new ( Kind :: ContactList , "" )
104+ . tags ( tags)
105+ . custom_created_at ( event_timestamp)
106+ . sign_with_keys ( & keys)
107+ . map_err ( |e| WhitenoiseError :: Other ( e. into ( ) ) ) ?;
108+
109+ client. send_event ( & event) . await ?;
106110 tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 1 ) ) . await ;
107111 client. disconnect ( ) . await ;
108112 Ok ( ( ) )
109113 }
110114
111- async fn publish_global_metadata_event (
115+ async fn publish_global_metadata_event_with_timestamp (
112116 & self ,
113117 context : & ScenarioContext ,
118+ event_timestamp : Timestamp ,
114119 ) -> Result < ( ) , WhitenoiseError > {
115- let ext = Keys :: generate ( ) ;
116- let client = create_test_client ( & context. dev_relays , ext ) . await ?;
120+ let keys = Keys :: generate ( ) ;
121+ let client = create_test_client ( & context. dev_relays , keys . clone ( ) ) . await ?;
117122 let metadata = Metadata {
118- name : Some ( "No-op for account sync" . to_string ( ) ) ,
123+ name : Some ( "Test metadata for sync verification " . to_string ( ) ) ,
119124 ..Default :: default ( )
120125 } ;
121- client
122- . send_event_builder ( EventBuilder :: metadata ( & metadata) )
123- . await ?;
126+
127+ let event = EventBuilder :: metadata ( & metadata)
128+ . custom_created_at ( event_timestamp)
129+ . sign_with_keys ( & keys)
130+ . map_err ( |e| WhitenoiseError :: Other ( e. into ( ) ) ) ?;
131+
132+ client. send_event ( & event) . await ?;
124133 tokio:: time:: sleep ( tokio:: time:: Duration :: from_millis ( 600 ) ) . await ;
125134 client. disconnect ( ) . await ;
126135 Ok ( ( ) )
@@ -132,9 +141,37 @@ impl TestCase for VerifyLastSyncedTimestampTestCase {
132141 async fn run ( & self , context : & mut ScenarioContext ) -> Result < ( ) , WhitenoiseError > {
133142 let pubkey = { context. get_account ( "subscription_test_account" ) ?. pubkey } ;
134143 let before = self . baseline ( context, pubkey) . await ?;
144+
145+ // Create deterministic base timestamp for this test run
146+ let base_timestamp = Timestamp :: now ( ) ;
147+
135148 match self . mode {
136149 Mode :: AccountFollowEvent => {
137- self . publish_account_follow_event ( context, pubkey) . await ?;
150+ // Wait to ensure that when the event timestamp gets capped to now(),
151+ // it will still be greater than the baseline last_synced_at
152+ if let Some ( before_time) = before {
153+ let before_timestamp_secs = before_time. timestamp ( ) as u64 ;
154+ let current_timestamp_secs = Timestamp :: now ( ) . as_u64 ( ) ;
155+
156+ if current_timestamp_secs <= before_timestamp_secs {
157+ // Wait enough time to ensure now() > baseline when event gets processed
158+ let wait_time = ( before_timestamp_secs - current_timestamp_secs + 2 ) * 1000 ; // +2 seconds buffer
159+ tracing:: debug!(
160+ target: "verify_last_synced_timestamp" ,
161+ "Waiting {}ms to ensure capped timestamp > baseline ({} vs {})" ,
162+ wait_time,
163+ current_timestamp_secs,
164+ before_timestamp_secs
165+ ) ;
166+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( wait_time) ) . await ;
167+ }
168+ }
169+
170+ // Use base timestamp + 10 seconds for guaranteed advancement
171+ // Even if this gets capped to now(), it should be > baseline due to our wait
172+ let event_timestamp = Timestamp :: from_secs ( base_timestamp. as_u64 ( ) + 10 ) ;
173+ self . publish_account_follow_event_with_timestamp ( context, pubkey, event_timestamp)
174+ . await ?;
138175 self . assert_advanced (
139176 context,
140177 pubkey,
@@ -144,7 +181,10 @@ impl TestCase for VerifyLastSyncedTimestampTestCase {
144181 . await ?;
145182 }
146183 Mode :: GlobalMetadataEvent => {
147- self . publish_global_metadata_event ( context) . await ?;
184+ // Use base timestamp + 5 seconds (should not affect account sync)
185+ let event_timestamp = Timestamp :: from_secs ( base_timestamp. as_u64 ( ) + 5 ) ;
186+ self . publish_global_metadata_event_with_timestamp ( context, event_timestamp)
187+ . await ?;
148188 self . assert_unchanged (
149189 context,
150190 pubkey,
0 commit comments