func testHealthScheduler(t test.Tester) { now := time.Now() var scenarios = []struct { futureHealthState []TargetState preloadedTimes []time.Time expectedSchedule []time.Time }{ // The behavior discussed in healthScheduler.Reschedule should be read // fully to understand the whys and wherefores. { futureHealthState: []TargetState{UNKNOWN, ALIVE, ALIVE}, preloadedTimes: []time.Time{now, now.Add(time.Minute), now.Add(time.Minute * 2)}, expectedSchedule: []time.Time{now, now.Add(time.Minute), now.Add(time.Minute * 2)}, }, { futureHealthState: []TargetState{UNKNOWN, UNREACHABLE, UNREACHABLE}, preloadedTimes: []time.Time{now, now.Add(time.Minute), now.Add(time.Minute * 2)}, expectedSchedule: []time.Time{now, now.Add(time.Second * 2), now.Add(time.Minute).Add(time.Second * 4)}, }, { futureHealthState: []TargetState{UNKNOWN, UNREACHABLE, ALIVE}, preloadedTimes: []time.Time{now, now.Add(time.Minute), now.Add(time.Minute * 2)}, expectedSchedule: []time.Time{now, now.Add(time.Second * 2), now.Add(time.Minute * 2)}, }, { futureHealthState: []TargetState{UNKNOWN, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE}, preloadedTimes: []time.Time{now, now.Add(time.Minute), now.Add(time.Minute * 2), now.Add(time.Minute * 3), now.Add(time.Minute * 4), now.Add(time.Minute * 5), now.Add(time.Minute * 6), now.Add(time.Minute * 7), now.Add(time.Minute * 8), now.Add(time.Minute * 9), now.Add(time.Minute * 10), now.Add(time.Minute * 11), now.Add(time.Minute * 12)}, expectedSchedule: []time.Time{now, now.Add(time.Second * 2), now.Add(time.Minute * 1).Add(time.Second * 4), now.Add(time.Minute * 2).Add(time.Second * 8), now.Add(time.Minute * 3).Add(time.Second * 16), now.Add(time.Minute * 4).Add(time.Second * 32), now.Add(time.Minute * 5).Add(time.Second * 64), now.Add(time.Minute * 6).Add(time.Second * 128), now.Add(time.Minute * 7).Add(time.Second * 256), now.Add(time.Minute * 8).Add(time.Second * 512), now.Add(time.Minute * 9).Add(time.Second * 1024), now.Add(time.Minute * 10).Add(time.Minute * 30), now.Add(time.Minute * 11).Add(time.Minute * 30)}, }, } for i, scenario := range scenarios { provider := &fakeTimeProvider{} for _, time := range scenario.preloadedTimes { provider.timeQueue = append(provider.timeQueue, time) } reporter := fakeHealthReporter{} for _, state := range scenario.futureHealthState { reporter.stateQueue = append(reporter.stateQueue, state) } if len(scenario.preloadedTimes) != len(scenario.futureHealthState) || len(scenario.futureHealthState) != len(scenario.expectedSchedule) { t.Fatalf("%d. times and health reports and next time lengths were not equal.", i) } timer := timer{ provider: provider, } scheduler := healthScheduler{ timer: timer, target: reporter, scheduledFor: now, } for j := 0; j < len(scenario.preloadedTimes); j++ { futureState := scenario.futureHealthState[j] scheduler.Reschedule(scenario.preloadedTimes[j], futureState) nextSchedule := scheduler.ScheduledFor() if nextSchedule != scenario.expectedSchedule[j] { t.Errorf("%d.%d. Expected to be scheduled to %s, got %s", i, j, scenario.expectedSchedule[j], nextSchedule) } } } }
func testTargetPool(t test.Tester) { type expectation struct { size int } type input struct { address string scheduledFor time.Time } type output struct { address string } var scenarios = []struct { name string outputs []output inputs []input }{ { name: "empty", inputs: []input{}, outputs: []output{}, }, { name: "single element", inputs: []input{ { address: "http://single.com", }, }, outputs: []output{ { address: "http://single.com", }, }, }, { name: "plural descending schedules", inputs: []input{ { address: "http://plural-descending.com", scheduledFor: time.Date(2013, 1, 4, 12, 0, 0, 0, time.UTC), }, { address: "http://plural-descending.net", scheduledFor: time.Date(2013, 1, 4, 11, 0, 0, 0, time.UTC), }, }, outputs: []output{ { address: "http://plural-descending.net", }, { address: "http://plural-descending.com", }, }, }, { name: "plural ascending schedules", inputs: []input{ { address: "http://plural-ascending.net", scheduledFor: time.Date(2013, 1, 4, 11, 0, 0, 0, time.UTC), }, { address: "http://plural-ascending.com", scheduledFor: time.Date(2013, 1, 4, 12, 0, 0, 0, time.UTC), }, }, outputs: []output{ { address: "http://plural-ascending.net", }, { address: "http://plural-ascending.com", }, }, }, } for i, scenario := range scenarios { pool := TargetPool{} for _, input := range scenario.inputs { target := target{ address: input.address, scheduler: literalScheduler(input.scheduledFor), } heap.Push(&pool, &target) } targets := []Target{} if pool.Len() != len(scenario.outputs) { t.Errorf("%s %d. expected TargetPool size to be %d but was %d", scenario.name, i, len(scenario.outputs), pool.Len()) } else { for j, output := range scenario.outputs { target := heap.Pop(&pool).(Target) if target.Address() != output.address { t.Errorf("%s %d.%d. expected Target address to be %s but was %s", scenario.name, i, j, output.address, target.Address()) } targets = append(targets, target) } if pool.Len() != 0 { t.Errorf("%s %d. expected pool to be empty, had %d", scenario.name, i, pool.Len()) } if len(targets) != len(scenario.outputs) { t.Errorf("%s %d. expected to receive %d elements, got %d", scenario.name, i, len(scenario.outputs), len(targets)) } for _, target := range targets { heap.Push(&pool, target) } if pool.Len() != len(scenario.outputs) { t.Errorf("%s %d. expected to repopulated with %d elements, got %d", scenario.name, i, len(scenario.outputs), pool.Len()) } } } }