func TestCheckGCSBuilds(t *testing.T) { latestBuildNumberFoo := 42 latestBuildNumberBar := 44 latestBuildNumberBaz := 99 tests := []struct { paths map[string][]byte expectStable bool expectedLastBuild int expectedStatus map[string]BuildInfo }{ { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/baz/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBaz)), fmt.Sprintf("/baz/%v/finished.json", latestBuildNumberBaz): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), "/": genMockGCSListResponse(), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "99"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), "/baz/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBaz)), fmt.Sprintf("/baz/%v/finished.json", latestBuildNumberBaz): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/": genMockGCSListResponse(), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Not Stable", ID: "44"}, "baz": {Status: "[nonblocking] Stable", ID: "99"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar): getRealJUnitFailure(), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar-1): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 999, }, t), "/": genMockGCSListResponse( fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar), ), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Ignorable flake", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1): getOtherRealJUnitFailure(), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar): getRealJUnitFailure(), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar-1): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 999, }, t), "/": genMockGCSListResponse( fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar), ), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Ignorable flake", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1): getRealJUnitFailure(), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar): getRealJUnitFailure(), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar-1): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 999, }, t), "/": genMockGCSListResponse( fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar), ), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Not Stable", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "FAILURE", Timestamp: 1234, }, t), "/": genMockGCSListResponse(), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Not Stable", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "FAILURE", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), "/": genMockGCSListResponse(), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Not Stable", ID: "42"}, "bar": {Status: "Not Stable", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/": genMockGCSListResponse(), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Not Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, }, }, } for index, test := range tests { server := httptest.NewServer(&testHandler{ handler: func(res http.ResponseWriter, req *http.Request) { data, found := test.paths[req.URL.Path] if !found { res.WriteHeader(http.StatusNotFound) fmt.Fprintf(res, "Unknown path: %s", req.URL.Path) return } res.WriteHeader(http.StatusOK) res.Write(data) }, }) e2e := &RealE2ETester{ BlockingJobNames: []string{ "foo", "bar", }, NonBlockingJobNames: []string{ "baz", }, BuildStatus: map[string]BuildInfo{}, GoogleGCSBucketUtils: utils.NewTestUtils(server.URL), } e2e.Init(nil) stable, _ := e2e.GCSBasedStable() if stable != test.expectStable { t.Errorf("%v: expected: %v, saw: %v", index, test.expectStable, stable) } if !reflect.DeepEqual(test.expectedStatus, e2e.BuildStatus) { t.Errorf("%v: expected: %v, saw: %v", index, test.expectedStatus, e2e.BuildStatus) } } }
// internalInitialize will initialize the munger. // if overrideUrl is specified, will create testUtils func (sq *SubmitQueue) internalInitialize(config *github.Config, features *features.Features, overrideUrl string) error { sq.Lock() defer sq.Unlock() // Clean up all of our flags which we wish --flag="" to mean []string{} sq.BlockingJobNames = cleanStringSlice(sq.BlockingJobNames) sq.NonBlockingJobNames = cleanStringSlice(sq.NonBlockingJobNames) sq.PresubmitJobNames = cleanStringSlice(sq.PresubmitJobNames) sq.WeakStableJobNames = cleanStringSlice(sq.WeakStableJobNames) sq.RequiredStatusContexts = cleanStringSlice(sq.RequiredStatusContexts) sq.RequiredRetestContexts = cleanStringSlice(sq.RequiredRetestContexts) sq.DoNotMergeMilestones = cleanStringSlice(sq.DoNotMergeMilestones) sq.Metadata.RepoPullUrl = fmt.Sprintf("https://github.com/%s/%s/pulls/", config.Org, config.Project) sq.Metadata.ProjectName = strings.Title(config.Project) sq.githubConfig = config // TODO: This is not how injection for tests should work. if sq.FakeE2E { sq.e2e = &fake_e2e.FakeE2ETester{ JobNames: sq.BlockingJobNames, WeakStableJobNames: sq.WeakStableJobNames, } } else { var gcs *utils.Utils if overrideUrl != "" { gcs = utils.NewTestUtils("bucket", "logs", overrideUrl) } else { gcs = utils.NewWithPresubmitDetection( sq.features.GCSInfo.BucketName, sq.features.GCSInfo.LogDir, sq.features.GCSInfo.PullKey, sq.features.GCSInfo.PullLogDir, ) } sq.e2e = (&e2e.RealE2ETester{ BlockingJobNames: sq.BlockingJobNames, NonBlockingJobNames: sq.NonBlockingJobNames, WeakStableJobNames: sq.WeakStableJobNames, BuildStatus: map[string]e2e.BuildInfo{}, GoogleGCSBucketUtils: gcs, }).Init(admin.Mux) } sq.lgtmTimeCache = mungerutil.NewLabelTimeCache(lgtmLabel) if len(config.Address) > 0 { if len(config.WWWRoot) > 0 { http.Handle("/", gziphandler.GzipHandler(http.FileServer(http.Dir(config.WWWRoot)))) } http.Handle("/prs", gziphandler.GzipHandler(http.HandlerFunc(sq.servePRs))) http.Handle("/history", gziphandler.GzipHandler(http.HandlerFunc(sq.serveHistory))) http.Handle("/github-e2e-queue", gziphandler.GzipHandler(http.HandlerFunc(sq.serveGithubE2EStatus))) http.Handle("/google-internal-ci", gziphandler.GzipHandler(http.HandlerFunc(sq.serveGoogleInternalStatus))) http.Handle("/merge-info", gziphandler.GzipHandler(http.HandlerFunc(sq.serveMergeInfo))) http.Handle("/priority-info", gziphandler.GzipHandler(http.HandlerFunc(sq.servePriorityInfo))) http.Handle("/health", gziphandler.GzipHandler(http.HandlerFunc(sq.serveHealth))) http.Handle("/health.svg", gziphandler.GzipHandler(http.HandlerFunc(sq.serveHealthSVG))) http.Handle("/sq-stats", gziphandler.GzipHandler(http.HandlerFunc(sq.serveSQStats))) http.Handle("/flakes", gziphandler.GzipHandler(http.HandlerFunc(sq.serveFlakes))) http.Handle("/metadata", gziphandler.GzipHandler(http.HandlerFunc(sq.serveMetadata))) config.ServeDebugStats("/stats") go http.ListenAndServe(config.Address, nil) } admin.Mux.HandleFunc("/api/emergency/stop", sq.EmergencyStopHTTP) admin.Mux.HandleFunc("/api/emergency/resume", sq.EmergencyStopHTTP) admin.Mux.HandleFunc("/api/emergency/status", sq.EmergencyStopHTTP) if sq.githubE2EPollTime == 0 { sq.githubE2EPollTime = githubE2EPollTime } sq.healthHistory = make([]healthRecord, 0) go sq.handleGithubE2EAndMerge() go sq.updateGoogleE2ELoop() if sq.AdminPort != 0 { go http.ListenAndServe(fmt.Sprintf("0.0.0.0:%v", sq.AdminPort), admin.Mux) } return nil }
func TestCheckGCSWeakBuilds(t *testing.T) { latestBuildNumberFoo := 42 latestBuildNumberBar := 44 tests := []struct { paths map[string][]byte expectStable bool expectedLastBuild int expectedStatus map[string]BuildInfo }{ // Simple case - both succeeds { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, }, }, // If last build was successful we shouldn't be looking any further { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo-1): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar-1): marshalOrDie(utils.FinishedFile{ Result: "FAILURE", Timestamp: 1234, }, t), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, }, }, // If the last build was unsuccessful but there's no failures in JUnit file we assume that it was // an infrastructure failure. Build should succeed if at least one of two builds were fully successful. { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/foo/%v/artifacts/junit_01.xml", latestBuildNumberFoo): getJUnit(5, 0), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo-1): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1233, }, t), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo-2): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1232, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), }, expectStable: true, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, }, }, // If the last build was unsuccessful but there's no failures in JUnit file we assume that it was // an infrastructure failure. Build should fail more than both recent builds failed. { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/foo/%v/artifacts/junit_01.xml", latestBuildNumberFoo): getJUnit(5, 0), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo-1): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1233, }, t), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo-2): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1232, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Not Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, }, }, // If the last build was unsuccessful and there's a failed test in a JUnit file we should fail. { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "UNSTABLE", Timestamp: 1234, }, t), fmt.Sprintf("/foo/%v/artifacts/junit_01.xml", latestBuildNumberFoo): getJUnit(5, 0), fmt.Sprintf("/foo/%v/artifacts/junit_02.xml", latestBuildNumberFoo): getJUnit(5, 1), fmt.Sprintf("/foo/%v/artifacts/junit_03.xml", latestBuildNumberFoo): getJUnit(5, 0), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Not Stable", ID: "42"}, "bar": {Status: "Stable", ID: "44"}, }, }, // Result shouldn't depend on order. { paths: map[string][]byte{ "/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), fmt.Sprintf("/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ Result: "SUCCESS", Timestamp: 1234, }, t), "/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), fmt.Sprintf("/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ Result: "FAILURE", Timestamp: 1234, }, t), fmt.Sprintf("/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar): getJUnit(5, 0), fmt.Sprintf("/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar): getJUnit(5, 1), fmt.Sprintf("/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar): getJUnit(5, 1), }, expectStable: false, expectedStatus: map[string]BuildInfo{ "foo": {Status: "Stable", ID: "42"}, "bar": {Status: "Not Stable", ID: "44"}, }, }, } for _, test := range tests { server := httptest.NewServer(&testHandler{ handler: func(res http.ResponseWriter, req *http.Request) { data, found := test.paths[req.URL.Path] if !found { res.WriteHeader(http.StatusNotFound) fmt.Fprintf(res, "Unknown path: %s", req.URL.Path) return } res.WriteHeader(http.StatusOK) res.Write(data) }, }) e2e := &RealE2ETester{ WeakStableJobNames: []string{ "foo", "bar", }, BuildStatus: map[string]BuildInfo{}, GoogleGCSBucketUtils: utils.NewTestUtils(server.URL), } e2e.Init(nil) stable := e2e.GCSWeakStable() if stable != test.expectStable { t.Errorf("expected: %v, saw: %v", test.expectStable, stable) } if !reflect.DeepEqual(test.expectedStatus, e2e.BuildStatus) { t.Errorf("expected: %v, saw: %v", test.expectedStatus, e2e.BuildStatus) } } }