@@ -2089,6 +2089,188 @@ func TestScheduler_OneTimeJob(t *testing.T) {
2089
2089
}
2090
2090
}
2091
2091
2092
+ func TestScheduler_AtTimesJob (t * testing.T ) {
2093
+ defer verifyNoGoroutineLeaks (t )
2094
+
2095
+ n := time .Now ().UTC ()
2096
+
2097
+ tests := []struct {
2098
+ name string
2099
+ atTimes []time.Time
2100
+ fakeClock clockwork.FakeClock
2101
+ assertErr require.ErrorAssertionFunc
2102
+ // asserts things about schedules, advance time and perform new assertions
2103
+ advanceAndAsserts []func (
2104
+ t * testing.T ,
2105
+ j Job ,
2106
+ clock clockwork.FakeClock ,
2107
+ runs * atomic.Uint32 ,
2108
+ )
2109
+ }{
2110
+ {
2111
+ name : "no at times" ,
2112
+ atTimes : []time.Time {},
2113
+ fakeClock : clockwork .NewFakeClock (),
2114
+ assertErr : func (t require.TestingT , err error , i ... interface {}) {
2115
+ require .ErrorIs (t , err , ErrOneTimeJobStartDateTimePast )
2116
+ },
2117
+ },
2118
+ {
2119
+ name : "all in the past" ,
2120
+ atTimes : []time.Time {n .Add (- 1 * time .Second )},
2121
+ fakeClock : clockwork .NewFakeClockAt (n ),
2122
+ assertErr : func (t require.TestingT , err error , i ... interface {}) {
2123
+ require .ErrorIs (t , err , ErrOneTimeJobStartDateTimePast )
2124
+ },
2125
+ },
2126
+ {
2127
+ name : "one run 1 millisecond in the future" ,
2128
+ atTimes : []time.Time {n .Add (1 * time .Millisecond )},
2129
+ fakeClock : clockwork .NewFakeClockAt (n ),
2130
+ advanceAndAsserts : []func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ){
2131
+ func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ) {
2132
+ require .Equal (t , uint32 (0 ), runs .Load ())
2133
+
2134
+ // last not initialized
2135
+ lastRunAt , err := j .LastRun ()
2136
+ require .NoError (t , err )
2137
+ require .Equal (t , time.Time {}, lastRunAt )
2138
+
2139
+ // next is now
2140
+ nextRunAt , err := j .NextRun ()
2141
+ require .NoError (t , err )
2142
+ require .Equal (t , n .Add (1 * time .Millisecond ), nextRunAt )
2143
+
2144
+ // advance and eventually run
2145
+ clock .Advance (2 * time .Millisecond )
2146
+ require .Eventually (t , func () bool {
2147
+ return assert .Equal (t , uint32 (1 ), runs .Load ())
2148
+ }, 3 * time .Second , 100 * time .Millisecond )
2149
+
2150
+ // last was run
2151
+ lastRunAt , err = j .LastRun ()
2152
+ require .NoError (t , err )
2153
+ require .WithinDuration (t , n .Add (1 * time .Millisecond ), lastRunAt , 1 * time .Millisecond )
2154
+
2155
+ nextRunAt , err = j .NextRun ()
2156
+ require .NoError (t , err )
2157
+ require .Equal (t , time.Time {}, nextRunAt )
2158
+ },
2159
+ },
2160
+ },
2161
+ {
2162
+ name : "one run in the past and one in the future" ,
2163
+ atTimes : []time.Time {n .Add (- 1 * time .Millisecond ), n .Add (1 * time .Millisecond )},
2164
+ fakeClock : clockwork .NewFakeClockAt (n ),
2165
+ advanceAndAsserts : []func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ){
2166
+ func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ) {
2167
+ require .Equal (t , uint32 (0 ), runs .Load ())
2168
+
2169
+ // last not initialized
2170
+ lastRunAt , err := j .LastRun ()
2171
+ require .NoError (t , err )
2172
+ require .Equal (t , time.Time {}, lastRunAt )
2173
+
2174
+ // next is now
2175
+ nextRunAt , err := j .NextRun ()
2176
+ require .NoError (t , err )
2177
+ require .Equal (t , n .Add (1 * time .Millisecond ), nextRunAt )
2178
+
2179
+ // advance and eventually run
2180
+ clock .Advance (2 * time .Millisecond )
2181
+ require .Eventually (t , func () bool {
2182
+ return assert .Equal (t , uint32 (1 ), runs .Load ())
2183
+ }, 3 * time .Second , 100 * time .Millisecond )
2184
+
2185
+ // last was run
2186
+ lastRunAt , err = j .LastRun ()
2187
+ require .NoError (t , err )
2188
+ require .WithinDuration (t , n .Add (1 * time .Millisecond ), lastRunAt , 1 * time .Millisecond )
2189
+ },
2190
+ },
2191
+ },
2192
+ {
2193
+ name : "two runs in the future" ,
2194
+ atTimes : []time.Time {n .Add (1 * time .Millisecond ), n .Add (3 * time .Millisecond )},
2195
+ fakeClock : clockwork .NewFakeClockAt (n ),
2196
+ advanceAndAsserts : []func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ){
2197
+ func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ) {
2198
+ require .Equal (t , uint32 (0 ), runs .Load ())
2199
+
2200
+ // last not initialized
2201
+ lastRunAt , err := j .LastRun ()
2202
+ require .NoError (t , err )
2203
+ require .Equal (t , time.Time {}, lastRunAt )
2204
+
2205
+ // next is now
2206
+ nextRunAt , err := j .NextRun ()
2207
+ require .NoError (t , err )
2208
+ require .Equal (t , n .Add (1 * time .Millisecond ), nextRunAt )
2209
+
2210
+ // advance and eventually run
2211
+ clock .Advance (2 * time .Millisecond )
2212
+ require .Eventually (t , func () bool {
2213
+ return assert .Equal (t , uint32 (1 ), runs .Load ())
2214
+ }, 3 * time .Second , 100 * time .Millisecond )
2215
+
2216
+ // last was run
2217
+ lastRunAt , err = j .LastRun ()
2218
+ require .NoError (t , err )
2219
+ require .WithinDuration (t , n .Add (1 * time .Millisecond ), lastRunAt , 1 * time .Millisecond )
2220
+
2221
+ nextRunAt , err = j .NextRun ()
2222
+ require .NoError (t , err )
2223
+ require .Equal (t , n .Add (3 * time .Millisecond ), nextRunAt )
2224
+ },
2225
+
2226
+ func (t * testing.T , j Job , clock clockwork.FakeClock , runs * atomic.Uint32 ) {
2227
+ // advance and eventually run
2228
+ clock .Advance (2 * time .Millisecond )
2229
+ require .Eventually (t , func () bool {
2230
+ return assert .Equal (t , uint32 (2 ), runs .Load ())
2231
+ }, 3 * time .Second , 100 * time .Millisecond )
2232
+
2233
+ // last was run
2234
+ lastRunAt , err := j .LastRun ()
2235
+ require .NoError (t , err )
2236
+ require .WithinDuration (t , n .Add (3 * time .Millisecond ), lastRunAt , 1 * time .Millisecond )
2237
+
2238
+ nextRunAt , err := j .NextRun ()
2239
+ require .NoError (t , err )
2240
+ require .Equal (t , time.Time {}, nextRunAt )
2241
+ },
2242
+ },
2243
+ },
2244
+ }
2245
+
2246
+ for _ , tt := range tests {
2247
+ t .Run (tt .name , func (t * testing.T ) {
2248
+ s := newTestScheduler (t , WithClock (tt .fakeClock ))
2249
+ t .Cleanup (func () {
2250
+ require .NoError (t , s .Shutdown ())
2251
+ })
2252
+
2253
+ runs := atomic.Uint32 {}
2254
+ j , err := s .NewJob (
2255
+ OneTimeJob (OneTimeJobStartDateTimes (tt .atTimes ... )),
2256
+ NewTask (func () {
2257
+ runs .Add (1 )
2258
+ }),
2259
+ )
2260
+ if tt .assertErr != nil {
2261
+ tt .assertErr (t , err )
2262
+ } else {
2263
+ require .NoError (t , err )
2264
+ s .Start ()
2265
+
2266
+ for _ , advanceAndAssert := range tt .advanceAndAsserts {
2267
+ advanceAndAssert (t , j , tt .fakeClock , & runs )
2268
+ }
2269
+ }
2270
+ })
2271
+ }
2272
+ }
2273
+
2092
2274
func TestScheduler_WithLimitedRuns (t * testing.T ) {
2093
2275
defer verifyNoGoroutineLeaks (t )
2094
2276
0 commit comments