@@ -31,15 +31,15 @@ public DurableCursorWithUpdatesTests()
3131 . Callback < Uri , StorageContent , CancellationToken > ( ( u , sc , c ) => _savedStorageContent = sc ) ;
3232
3333 _cursor = new DurableCursorWithUpdates ( _address , _storage . Object , _defaultValue , Mock . Of < ILogger > ( ) ,
34- maxNumberOfUpdatesToKeep : 2 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( 60 ) ) ;
34+ maxNumberOfUpdatesToKeep : 2 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( 60 ) , minIntervalBeforeToReadUpdate : TimeSpan . FromSeconds ( 1 ) ) ;
3535 _cursor . Value = new DateTime ( 2026 , 1 , 1 , 1 , 0 , 0 , DateTimeKind . Unspecified ) ;
3636 }
3737
3838 [ Fact ]
3939 public void ThrowArgumentOutOfRangeException_maxNumberOfUpdatesToKeep ( )
4040 {
4141 var exception = Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new DurableCursorWithUpdates ( _address , It . IsAny < Storage > ( ) , _defaultValue , Mock . Of < ILogger > ( ) ,
42- maxNumberOfUpdatesToKeep : - 1 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( 60 ) ) ) ;
42+ maxNumberOfUpdatesToKeep : - 1 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( 60 ) , minIntervalBeforeToReadUpdate : TimeSpan . FromSeconds ( 1 ) ) ) ;
4343
4444 Assert . Equal ( "maxNumberOfUpdatesToKeep" , exception . ParamName ) ;
4545 Assert . Equal ( "maxNumberOfUpdatesToKeep must be equal or larger than 0.\r \n Parameter name: maxNumberOfUpdatesToKeep" , exception . Message ) ;
@@ -49,12 +49,22 @@ public void ThrowArgumentOutOfRangeException_maxNumberOfUpdatesToKeep()
4949 public void ThrowArgumentOutOfRangeException_minIntervalBetweenTwoUpdates ( )
5050 {
5151 var exception = Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new DurableCursorWithUpdates ( _address , It . IsAny < Storage > ( ) , _defaultValue , Mock . Of < ILogger > ( ) ,
52- maxNumberOfUpdatesToKeep : 2 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( - 1 ) ) ) ;
52+ maxNumberOfUpdatesToKeep : 2 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( - 1 ) , minIntervalBeforeToReadUpdate : TimeSpan . FromSeconds ( 1 ) ) ) ;
5353
5454 Assert . Equal ( "minIntervalBetweenTwoUpdates" , exception . ParamName ) ;
5555 Assert . Equal ( "minIntervalBetweenTwoUpdates must be equal or larger than 0.\r \n Parameter name: minIntervalBetweenTwoUpdates" , exception . Message ) ;
5656 }
5757
58+ [ Fact ]
59+ public void ThrowArgumentOutOfRangeException_minIntervalBeforeToReadUpdate ( )
60+ {
61+ var exception = Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new DurableCursorWithUpdates ( _address , It . IsAny < Storage > ( ) , _defaultValue , Mock . Of < ILogger > ( ) ,
62+ maxNumberOfUpdatesToKeep : 2 , minIntervalBetweenTwoUpdates : TimeSpan . FromSeconds ( 60 ) , minIntervalBeforeToReadUpdate : TimeSpan . FromSeconds ( - 1 ) ) ) ;
63+
64+ Assert . Equal ( "minIntervalBeforeToReadUpdate" , exception . ParamName ) ;
65+ Assert . Equal ( "minIntervalBeforeToReadUpdate must be equal or larger than 0.\r \n Parameter name: minIntervalBeforeToReadUpdate" , exception . Message ) ;
66+ }
67+
5868 [ Fact ]
5969 public async Task SaveAsync_WithDoesNotExistInStorage ( )
6070 {
@@ -63,15 +73,18 @@ public async Task SaveAsync_WithDoesNotExistInStorage()
6373
6474 Assert . NotNull ( _savedStorageContent ) ;
6575 Assert . IsType < StringStorageContent > ( _savedStorageContent ) ;
66- Assert . Equal ( "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ,\" updates\" :[]}" , ( _savedStorageContent as StringStorageContent ) . Content ) ;
76+ Assert . Equal ( "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ,\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ,\" updates\" :[]}" ,
77+ ( _savedStorageContent as StringStorageContent ) . Content ) ;
6778
6879 _storage . Verify ( s => s . LoadStringStorageContentAsync ( It . IsAny < Uri > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
6980 _storage . Verify ( s => s . SaveAsync ( It . IsAny < Uri > ( ) , It . IsAny < StorageContent > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
7081 }
7182
7283 [ Theory ]
7384 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" }" ) ]
85+ [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ,\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" }" ) ]
7486 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ,\" updates\" :[]}" ) ]
87+ [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ,\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ,\" updates\" :[]}" ) ]
7588 public async Task SaveAsync_WithEmptyUpdatesInStorage ( string content )
7689 {
7790 _storageContent = new StringStorageContent ( content , storageDateTimeInUtc : new DateTime ( 2026 , 1 , 1 , 1 , 0 , 30 , DateTimeKind . Utc ) ) ;
@@ -80,6 +93,25 @@ public async Task SaveAsync_WithEmptyUpdatesInStorage(string content)
8093 Assert . NotNull ( _savedStorageContent ) ;
8194 Assert . IsType < StringStorageContent > ( _savedStorageContent ) ;
8295 Assert . Equal ( "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
96+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
97+ "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }]}" ,
98+ ( _savedStorageContent as StringStorageContent ) . Content ) ;
99+
100+ _storage . Verify ( s => s . LoadStringStorageContentAsync ( It . IsAny < Uri > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
101+ _storage . Verify ( s => s . SaveAsync ( It . IsAny < Uri > ( ) , It . IsAny < StorageContent > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
102+ }
103+
104+ [ Fact ]
105+ public async Task SaveAsync_WithDifferentMinInterval ( )
106+ {
107+ _storageContent = new StringStorageContent ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ,\" minIntervalBeforeToReadUpdate\" :\" 01:01:01\" }" ,
108+ storageDateTimeInUtc : new DateTime ( 2026 , 1 , 1 , 1 , 0 , 30 , DateTimeKind . Utc ) ) ;
109+ await _cursor . SaveAsync ( CancellationToken . None ) ;
110+
111+ Assert . NotNull ( _savedStorageContent ) ;
112+ Assert . IsType < StringStorageContent > ( _savedStorageContent ) ;
113+ Assert . Equal ( "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
114+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
83115 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }]}" ,
84116 ( _savedStorageContent as StringStorageContent ) . Content ) ;
85117
@@ -89,41 +121,53 @@ public async Task SaveAsync_WithEmptyUpdatesInStorage(string content)
89121
90122 [ Theory ]
91123 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
124+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
92125 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ,
93126 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
127+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
94128 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }," +
95129 "{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ) ]
96130 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
131+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
97132 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
98133 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }]}" ,
99134 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
135+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
100136 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }," +
101137 "{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ) ]
102138 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
139+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
103140 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
104141 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }," +
105142 "{\" timeStamp\" :\" 2026-01-01T00:57:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:57:00.0000000\" }]}" ,
106143 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
144+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
107145 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }," +
108146 "{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ) ]
109147 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
148+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
110149 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }," +
111150 "{\" timeStamp\" :\" 2026-01-01T00:57:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:57:00.0000000\" }," +
112151 "{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ,
113152 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
153+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
114154 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T01:00:30.0000000Z\" ,\" value\" :\" 2026-01-01T01:00:00.0000000\" }," +
115155 "{\" timeStamp\" :\" 2026-01-01T00:59:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }]}" ) ]
116156 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
157+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
117158 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:31.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
118159 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }]}" ,
119160 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
161+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
120162 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:31.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
121163 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }]}" ) ]
122164 [ InlineData ( "{\" value\" :\" 2026-01-01T00:59:00.0000000\" ," +
165+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
123166 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:31.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
124167 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }," +
125168 "{\" timeStamp\" :\" 2026-01-01T00:57:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:57:00.0000000\" }]}" ,
126169 "{\" value\" :\" 2026-01-01T01:00:00.0000000\" ," +
170+ "\" minIntervalBeforeToReadUpdate\" :\" 00:00:01\" ," +
127171 "\" updates\" :[{\" timeStamp\" :\" 2026-01-01T00:59:31.0000000Z\" ,\" value\" :\" 2026-01-01T00:59:00.0000000\" }," +
128172 "{\" timeStamp\" :\" 2026-01-01T00:58:30.0000000Z\" ,\" value\" :\" 2026-01-01T00:58:00.0000000\" }]}" ) ]
129173 public async Task SaveAsync ( string content , string expectedContentAfterSave )
0 commit comments