func (f *fakeJobControl) CreateJob(namespace string, job *batch.Job) (*batch.Job, error) { f.Lock() defer f.Unlock() if f.Err != nil { return nil, f.Err } f.Jobs = append(f.Jobs, *job) job.UID = "test-uid" return job, nil }
func (f *fakeJobControl) CreateJob(namespace string, job *batch.Job) (*batch.Job, error) { f.Lock() defer f.Unlock() if f.Err != nil { return nil, f.Err } job.SelfLink = fmt.Sprintf("/api/batch/v1/namespaces/%s/jobs/%s", namespace, job.Name) f.Jobs = append(f.Jobs, *job) job.UID = "test-uid" return job, nil }
func TestSyncOne_RunOrNot(t *testing.T) { testCases := map[string]struct { // sj spec concurrencyPolicy batch.ConcurrencyPolicy suspend bool schedule string deadline int64 // sj status ranPreviously bool stillActive bool // environment now time.Time // expectations expectCreate bool expectDelete bool expectActive int }{ "never ran, not time, A": {A, F, onTheHour, noDead, F, F, justBeforeTheHour(), F, F, 0}, "never ran, not time, F": {f, F, onTheHour, noDead, F, F, justBeforeTheHour(), F, F, 0}, "never ran, not time, R": {R, F, onTheHour, noDead, F, F, justBeforeTheHour(), F, F, 0}, "never ran, is time, A": {A, F, onTheHour, noDead, F, F, justAfterTheHour(), T, F, 1}, "never ran, is time, F": {f, F, onTheHour, noDead, F, F, justAfterTheHour(), T, F, 1}, "never ran, is time, R": {R, F, onTheHour, noDead, F, F, justAfterTheHour(), T, F, 1}, "never ran, is time, suspended": {A, T, onTheHour, noDead, F, F, justAfterTheHour(), F, F, 0}, "never ran, is time, past deadline": {A, F, onTheHour, shortDead, F, F, justAfterTheHour(), F, F, 0}, "never ran, is time, not past deadline": {A, F, onTheHour, longDead, F, F, justAfterTheHour(), T, F, 1}, "prev ran but done, not time, A": {A, F, onTheHour, noDead, T, F, justBeforeTheHour(), F, F, 0}, "prev ran but done, not time, F": {f, F, onTheHour, noDead, T, F, justBeforeTheHour(), F, F, 0}, "prev ran but done, not time, R": {R, F, onTheHour, noDead, T, F, justBeforeTheHour(), F, F, 0}, "prev ran but done, is time, A": {A, F, onTheHour, noDead, T, F, justAfterTheHour(), T, F, 1}, "prev ran but done, is time, F": {f, F, onTheHour, noDead, T, F, justAfterTheHour(), T, F, 1}, "prev ran but done, is time, R": {R, F, onTheHour, noDead, T, F, justAfterTheHour(), T, F, 1}, "prev ran but done, is time, suspended": {A, T, onTheHour, noDead, T, F, justAfterTheHour(), F, F, 0}, "prev ran but done, is time, past deadline": {A, F, onTheHour, shortDead, T, F, justAfterTheHour(), F, F, 0}, "prev ran but done, is time, not past deadline": {A, F, onTheHour, longDead, T, F, justAfterTheHour(), T, F, 1}, "still active, not time, A": {A, F, onTheHour, noDead, T, T, justBeforeTheHour(), F, F, 1}, "still active, not time, F": {f, F, onTheHour, noDead, T, T, justBeforeTheHour(), F, F, 1}, "still active, not time, R": {R, F, onTheHour, noDead, T, T, justBeforeTheHour(), F, F, 1}, "still active, is time, A": {A, F, onTheHour, noDead, T, T, justAfterTheHour(), T, F, 2}, "still active, is time, F": {f, F, onTheHour, noDead, T, T, justAfterTheHour(), F, F, 1}, "still active, is time, R": {R, F, onTheHour, noDead, T, T, justAfterTheHour(), T, T, 1}, "still active, is time, suspended": {A, T, onTheHour, noDead, T, T, justAfterTheHour(), F, F, 1}, "still active, is time, past deadline": {A, F, onTheHour, shortDead, T, T, justAfterTheHour(), F, F, 1}, "still active, is time, not past deadline": {A, F, onTheHour, longDead, T, T, justAfterTheHour(), T, F, 2}, } for name, tc := range testCases { sj := scheduledJob() sj.Spec.ConcurrencyPolicy = tc.concurrencyPolicy sj.Spec.Suspend = &tc.suspend sj.Spec.Schedule = tc.schedule if tc.deadline != noDead { sj.Spec.StartingDeadlineSeconds = &tc.deadline } var ( job *batch.Job err error ) js := []batch.Job{} if tc.ranPreviously { sj.ObjectMeta.CreationTimestamp = unversioned.Time{Time: justBeforeThePriorHour()} sj.Status.LastScheduleTime = &unversioned.Time{Time: justAfterThePriorHour()} job, err = getJobFromTemplate(&sj, sj.Status.LastScheduleTime.Time) if err != nil { t.Fatalf("%s: nexpected error creating a job from template: %v", name, err) } job.UID = "1234" job.Namespace = "" if tc.stillActive { sj.Status.Active = []api.ObjectReference{{UID: job.UID}} js = append(js, *job) } } else { sj.ObjectMeta.CreationTimestamp = unversioned.Time{Time: justBeforeTheHour()} if tc.stillActive { t.Errorf("%s: test setup error: this case makes no sense", name) } } jc := &fakeJobControl{Job: job} sjc := &fakeSJControl{} pc := &fakePodControl{} recorder := record.NewFakeRecorder(10) SyncOne(sj, js, tc.now, jc, sjc, pc, recorder) expectedCreates := 0 if tc.expectCreate { expectedCreates = 1 } if len(jc.Jobs) != expectedCreates { t.Errorf("%s: expected %d job started, actually %v", name, expectedCreates, len(jc.Jobs)) } expectedDeletes := 0 if tc.expectDelete { expectedDeletes = 1 } if len(jc.DeleteJobName) != expectedDeletes { t.Errorf("%s: expected %d job deleted, actually %v", name, expectedDeletes, len(jc.DeleteJobName)) } // Status update happens once when ranging through job list, and another one if create jobs. expectUpdates := 1 expectedEvents := 0 if tc.expectCreate { expectedEvents++ expectUpdates++ } if tc.expectDelete { expectedEvents++ } if len(recorder.Events) != expectedEvents { t.Errorf("%s: expected %d event, actually %v", name, expectedEvents, len(recorder.Events)) } if tc.expectActive != len(sjc.Updates[expectUpdates-1].Status.Active) { t.Errorf("%s: expected Active size %d, got %d", name, tc.expectActive, len(sjc.Updates[expectUpdates-1].Status.Active)) } } }