github.com/uchennaokeke444/nomad@v0.11.8/nomad/structs/structs_periodic_test.go (about) 1 package structs 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestPeriodicConfig_DSTChange_Transitions(t *testing.T) { 14 locName := "America/Los_Angeles" 15 loc, err := time.LoadLocation(locName) 16 require.NoError(t, err) 17 18 cases := []struct { 19 name string 20 pattern string 21 initTime time.Time 22 expected []time.Time 23 }{ 24 { 25 "normal time", 26 "0 2 * * * 2019", 27 time.Date(2019, time.February, 7, 1, 0, 0, 0, loc), 28 []time.Time{ 29 time.Date(2019, time.February, 7, 2, 0, 0, 0, loc), 30 time.Date(2019, time.February, 8, 2, 0, 0, 0, loc), 31 time.Date(2019, time.February, 9, 2, 0, 0, 0, loc), 32 }, 33 }, 34 { 35 "Spring forward but not in switch time", 36 "0 4 * * * 2019", 37 time.Date(2019, time.March, 9, 1, 0, 0, 0, loc), 38 []time.Time{ 39 time.Date(2019, time.March, 9, 4, 0, 0, 0, loc), 40 time.Date(2019, time.March, 10, 4, 0, 0, 0, loc), 41 time.Date(2019, time.March, 11, 4, 0, 0, 0, loc), 42 }, 43 }, 44 { 45 "Spring forward at a skipped time odd", 46 "2 2 * * * 2019", 47 time.Date(2019, time.March, 9, 1, 0, 0, 0, loc), 48 []time.Time{ 49 time.Date(2019, time.March, 9, 2, 2, 0, 0, loc), 50 // no time in March 10! 51 time.Date(2019, time.March, 11, 2, 2, 0, 0, loc), 52 time.Date(2019, time.March, 12, 2, 2, 0, 0, loc), 53 }, 54 }, 55 { 56 "Spring forward at a skipped time", 57 "1 2 * * * 2019", 58 time.Date(2019, time.March, 9, 1, 0, 0, 0, loc), 59 []time.Time{ 60 time.Date(2019, time.March, 9, 2, 1, 0, 0, loc), 61 // no time in March 8! 62 time.Date(2019, time.March, 11, 2, 1, 0, 0, loc), 63 time.Date(2019, time.March, 12, 2, 1, 0, 0, loc), 64 }, 65 }, 66 { 67 "Spring forward at a skipped time boundary", 68 "0 2 * * * 2019", 69 time.Date(2019, time.March, 9, 1, 0, 0, 0, loc), 70 []time.Time{ 71 time.Date(2019, time.March, 9, 2, 0, 0, 0, loc), 72 // no time in March 8! 73 time.Date(2019, time.March, 11, 2, 0, 0, 0, loc), 74 time.Date(2019, time.March, 12, 2, 0, 0, 0, loc), 75 }, 76 }, 77 { 78 "Spring forward at a boundary of repeating time", 79 "0 1 * * * 2019", 80 time.Date(2019, time.March, 9, 0, 0, 0, 0, loc), 81 []time.Time{ 82 time.Date(2019, time.March, 9, 1, 0, 0, 0, loc), 83 time.Date(2019, time.March, 10, 0, 0, 0, 0, loc).Add(1 * time.Hour), 84 time.Date(2019, time.March, 11, 1, 0, 0, 0, loc), 85 time.Date(2019, time.March, 12, 1, 0, 0, 0, loc), 86 }, 87 }, 88 { 89 "Fall back: before transition", 90 "30 0 * * * 2019", 91 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 92 []time.Time{ 93 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc), 94 time.Date(2019, time.November, 4, 0, 30, 0, 0, loc), 95 time.Date(2019, time.November, 5, 0, 30, 0, 0, loc), 96 time.Date(2019, time.November, 6, 0, 30, 0, 0, loc), 97 }, 98 }, 99 { 100 "Fall back: after transition", 101 "30 3 * * * 2019", 102 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 103 []time.Time{ 104 time.Date(2019, time.November, 3, 3, 30, 0, 0, loc), 105 time.Date(2019, time.November, 4, 3, 30, 0, 0, loc), 106 time.Date(2019, time.November, 5, 3, 30, 0, 0, loc), 107 time.Date(2019, time.November, 6, 3, 30, 0, 0, loc), 108 }, 109 }, 110 { 111 "Fall back: after transition starting in repeated span before", 112 "30 3 * * * 2019", 113 time.Date(2019, time.November, 3, 0, 10, 0, 0, loc).Add(1 * time.Hour), 114 []time.Time{ 115 time.Date(2019, time.November, 3, 3, 30, 0, 0, loc), 116 time.Date(2019, time.November, 4, 3, 30, 0, 0, loc), 117 time.Date(2019, time.November, 5, 3, 30, 0, 0, loc), 118 time.Date(2019, time.November, 6, 3, 30, 0, 0, loc), 119 }, 120 }, 121 { 122 "Fall back: after transition starting in repeated span after", 123 "30 3 * * * 2019", 124 time.Date(2019, time.November, 3, 0, 10, 0, 0, loc).Add(2 * time.Hour), 125 []time.Time{ 126 time.Date(2019, time.November, 3, 3, 30, 0, 0, loc), 127 time.Date(2019, time.November, 4, 3, 30, 0, 0, loc), 128 time.Date(2019, time.November, 5, 3, 30, 0, 0, loc), 129 time.Date(2019, time.November, 6, 3, 30, 0, 0, loc), 130 }, 131 }, 132 { 133 "Fall back: in repeated region", 134 "30 1 * * * 2019", 135 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 136 []time.Time{ 137 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc).Add(1 * time.Hour), 138 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc).Add(2 * time.Hour), 139 time.Date(2019, time.November, 4, 1, 30, 0, 0, loc), 140 time.Date(2019, time.November, 5, 1, 30, 0, 0, loc), 141 time.Date(2019, time.November, 6, 1, 30, 0, 0, loc), 142 }, 143 }, 144 { 145 "Fall back: in repeated region boundary", 146 "0 1 * * * 2019", 147 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 148 []time.Time{ 149 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc).Add(1 * time.Hour), 150 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc).Add(2 * time.Hour), 151 time.Date(2019, time.November, 4, 1, 0, 0, 0, loc), 152 time.Date(2019, time.November, 5, 1, 0, 0, 0, loc), 153 time.Date(2019, time.November, 6, 1, 0, 0, 0, loc), 154 }, 155 }, 156 { 157 "Fall back: in repeated region boundary 2", 158 "0 2 * * * 2019", 159 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 160 []time.Time{ 161 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc).Add(3 * time.Hour), 162 time.Date(2019, time.November, 4, 2, 0, 0, 0, loc), 163 time.Date(2019, time.November, 5, 2, 0, 0, 0, loc), 164 time.Date(2019, time.November, 6, 2, 0, 0, 0, loc), 165 }, 166 }, 167 { 168 "Fall back: in repeated region, starting from within region", 169 "30 1 * * * 2019", 170 time.Date(2019, time.November, 3, 0, 40, 0, 0, loc).Add(1 * time.Hour), 171 []time.Time{ 172 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc).Add(2 * time.Hour), 173 time.Date(2019, time.November, 4, 1, 30, 0, 0, loc), 174 time.Date(2019, time.November, 5, 1, 30, 0, 0, loc), 175 time.Date(2019, time.November, 6, 1, 30, 0, 0, loc), 176 }, 177 }, 178 { 179 "Fall back: in repeated region, starting from within region 2", 180 "30 1 * * * 2019", 181 time.Date(2019, time.November, 3, 0, 40, 0, 0, loc).Add(2 * time.Hour), 182 []time.Time{ 183 time.Date(2019, time.November, 4, 1, 30, 0, 0, loc), 184 time.Date(2019, time.November, 5, 1, 30, 0, 0, loc), 185 time.Date(2019, time.November, 6, 1, 30, 0, 0, loc), 186 }, 187 }, 188 { 189 "Fall back: wildcard", 190 "30 * * * * 2019", 191 time.Date(2019, time.November, 3, 0, 0, 0, 0, loc), 192 []time.Time{ 193 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc), 194 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc).Add(1 * time.Hour), 195 time.Date(2019, time.November, 3, 0, 30, 0, 0, loc).Add(2 * time.Hour), 196 time.Date(2019, time.November, 3, 2, 30, 0, 0, loc), 197 }, 198 }, 199 } 200 201 for _, c := range cases { 202 t.Run(c.name, func(t *testing.T) { 203 p := &PeriodicConfig{ 204 Enabled: true, 205 SpecType: PeriodicSpecCron, 206 Spec: c.pattern, 207 TimeZone: locName, 208 } 209 p.Canonicalize() 210 211 starting := c.initTime 212 for _, next := range c.expected { 213 n, err := p.Next(starting) 214 assert.NoError(t, err) 215 assert.Equalf(t, next, n, "next time of %v", starting) 216 217 starting = next 218 } 219 }) 220 } 221 } 222 223 func TestPeriodConfig_DSTSprintForward_Property(t *testing.T) { 224 locName := "America/Los_Angeles" 225 loc, err := time.LoadLocation(locName) 226 require.NoError(t, err) 227 228 cronExprs := []string{ 229 "* * * * *", 230 "0 2 * * *", 231 "* 1 * * *", 232 } 233 234 times := []time.Time{ 235 // spring forward 236 time.Date(2019, time.March, 11, 0, 0, 0, 0, loc), 237 time.Date(2019, time.March, 10, 0, 0, 0, 0, loc), 238 time.Date(2019, time.March, 11, 0, 0, 0, 0, loc), 239 240 // leap backwards 241 time.Date(2019, time.November, 4, 0, 0, 0, 0, loc), 242 time.Date(2019, time.November, 5, 0, 0, 0, 0, loc), 243 time.Date(2019, time.November, 6, 0, 0, 0, 0, loc), 244 } 245 246 testSpan := 4 * time.Hour 247 248 testCase := func(t *testing.T, cronExpr string, init time.Time) { 249 p := &PeriodicConfig{ 250 Enabled: true, 251 SpecType: PeriodicSpecCron, 252 Spec: cronExpr, 253 TimeZone: "America/Los_Angeles", 254 } 255 p.Canonicalize() 256 257 lastNext := init 258 for start := init; start.Before(init.Add(testSpan)); start = start.Add(1 * time.Minute) { 259 next, err := p.Next(start) 260 require.NoError(t, err) 261 require.Truef(t, next.After(start), 262 "next(%v) = %v is not after init time", start, next) 263 264 if start.Before(lastNext) { 265 require.Equalf(t, lastNext, next, "next(%v) = %v is earlier than previously known next %v", 266 start, next, lastNext) 267 } 268 if strings.HasPrefix(cronExpr, "* * ") { 269 require.Equalf(t, next.Sub(start), 1*time.Minute, 270 "next(%v) = %v is the next minute", start, next) 271 } 272 273 lastNext = next 274 } 275 } 276 277 for _, cron := range cronExprs { 278 for _, startTime := range times { 279 t.Run(fmt.Sprintf("%v: %v", cron, startTime), func(t *testing.T) { 280 testCase(t, cron, startTime) 281 }) 282 } 283 } 284 }