go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/bqexporter/bqexporter_test.go (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bqexporter 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 . "github.com/smartystreets/goconvey/convey" 23 24 "go.chromium.org/luci/bisection/model" 25 bqpb "go.chromium.org/luci/bisection/proto/bq" 26 bisectionpb "go.chromium.org/luci/bisection/proto/v1" 27 "go.chromium.org/luci/bisection/util/testutil" 28 "go.chromium.org/luci/common/clock" 29 "go.chromium.org/luci/common/clock/testclock" 30 "go.chromium.org/luci/gae/impl/memory" 31 "go.chromium.org/luci/gae/service/datastore" 32 ) 33 34 func TestExport(t *testing.T) { 35 t.Parallel() 36 ctx := memory.Use(context.Background()) 37 testutil.UpdateIndices(ctx) 38 cl := testclock.New(testclock.TestTimeUTC) 39 baseTime := time.Unix(3600*24*30, 0).UTC() 40 cl.Set(baseTime) 41 ctx = clock.Set(ctx, cl) 42 43 Convey("export", t, func() { 44 // Create 5 test analyses. 45 for i := 1; i <= 5; i++ { 46 tfa := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 47 ID: int64(1000 + i), 48 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 49 Status: bisectionpb.AnalysisStatus(bisectionpb.AnalysisStatus_NOTFOUND), 50 CreateTime: clock.Now(ctx).Add(time.Hour * time.Duration(-i)), 51 }) 52 testutil.CreateTestFailure(ctx, &testutil.TestFailureCreationOption{ 53 ID: int64(2000 + i), 54 Analysis: tfa, 55 IsPrimary: true, 56 }) 57 } 58 59 client := &fakeExportClient{} 60 err := export(ctx, client) 61 So(err, ShouldBeNil) 62 // Filtered out 3. 63 So(len(client.rows), ShouldEqual, 2) 64 So(client.rows[0].AnalysisId, ShouldEqual, 1002) 65 So(client.rows[1].AnalysisId, ShouldEqual, 1004) 66 }) 67 } 68 func TestFetchTestAnalyses(t *testing.T) { 69 t.Parallel() 70 ctx := memory.Use(context.Background()) 71 testutil.UpdateIndices(ctx) 72 cl := testclock.New(testclock.TestTimeUTC) 73 baseTime := time.Unix(3600*24*30, 0).UTC() 74 cl.Set(baseTime) 75 ctx = clock.Set(ctx, cl) 76 77 Convey("fetch test analyses", t, func() { 78 // Not ended, should be skipped. 79 tf1 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 80 ID: 1001, 81 RunStatus: bisectionpb.AnalysisRunStatus_STARTED, 82 CreateTime: clock.Now(ctx).Add(-time.Hour), 83 }) 84 // Ended, but from a long time ago. Should be skipped. 85 tf2 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 86 ID: 1002, 87 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 88 CreateTime: clock.Now(ctx).Add(-15 * 24 * time.Hour), 89 }) 90 // Ended, not found. 91 tf3 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 92 ID: 1003, 93 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 94 Status: bisectionpb.AnalysisStatus(bisectionpb.AnalysisStatus_NOTFOUND), 95 CreateTime: clock.Now(ctx).Add(-time.Hour), 96 }) 97 // Ended, found, but action not taken, ended recently, should be skipped. 98 tf4 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 99 ID: 1004, 100 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 101 Status: bisectionpb.AnalysisStatus(bisectionpb.AnalysisStatus_FOUND), 102 CreateTime: clock.Now(ctx).Add(-time.Hour), 103 EndTime: clock.Now(ctx).Add(-time.Minute), 104 }) 105 createSuspect(ctx, tf4, false) 106 // Ended, found, actions taken. 107 tf5 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 108 ID: 1005, 109 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 110 Status: bisectionpb.AnalysisStatus(bisectionpb.AnalysisStatus_FOUND), 111 CreateTime: clock.Now(ctx).Add(-2 * time.Hour), 112 }) 113 createSuspect(ctx, tf5, true) 114 // Ended, found, but action not taken, ended long time ago. 115 tf6 := testutil.CreateTestFailureAnalysis(ctx, &testutil.TestFailureAnalysisCreationOption{ 116 ID: 1006, 117 RunStatus: bisectionpb.AnalysisRunStatus_ENDED, 118 Status: bisectionpb.AnalysisStatus(bisectionpb.AnalysisStatus_FOUND), 119 CreateTime: clock.Now(ctx).Add(-26 * time.Hour), 120 EndTime: clock.Now(ctx).Add(-25 * time.Hour), 121 }) 122 createSuspect(ctx, tf6, false) 123 So(datastore.Put(ctx, []*model.TestFailureAnalysis{tf1, tf2, tf3, tf4, tf5, tf6}), ShouldBeNil) 124 datastore.GetTestable(ctx).CatchupIndexes() 125 tfas, err := fetchTestAnalyses(ctx) 126 So(err, ShouldBeNil) 127 So(len(tfas), ShouldEqual, 3) 128 So(tfas[0].ID, ShouldEqual, 1003) 129 So(tfas[1].ID, ShouldEqual, 1005) 130 So(tfas[2].ID, ShouldEqual, 1006) 131 }) 132 } 133 134 func createSuspect(ctx context.Context, tfa *model.TestFailureAnalysis, hasTakenAction bool) { 135 suspect := &model.Suspect{ 136 Id: tfa.ID, 137 ActionDetails: model.ActionDetails{ 138 HasTakenActions: hasTakenAction, 139 }, 140 } 141 So(datastore.Put(ctx, suspect), ShouldBeNil) 142 datastore.GetTestable(ctx).CatchupIndexes() 143 tfa.VerifiedCulpritKey = datastore.KeyForObj(ctx, suspect) 144 } 145 146 // Fake client. 147 type fakeExportClient struct { 148 rows []*bqpb.TestAnalysisRow 149 } 150 151 func (cl *fakeExportClient) EnsureSchema(ctx context.Context) error { 152 return nil 153 } 154 155 func (cl *fakeExportClient) Insert(ctx context.Context, rows []*bqpb.TestAnalysisRow) error { 156 cl.rows = append(cl.rows, rows...) 157 return nil 158 } 159 160 func (cl *fakeExportClient) ReadTestFailureAnalysisRows(ctx context.Context) ([]*TestFailureAnalysisRow, error) { 161 return []*TestFailureAnalysisRow{ 162 { 163 AnalysisID: 1001, 164 }, 165 { 166 AnalysisID: 1003, 167 }, 168 { 169 AnalysisID: 1005, 170 }, 171 }, nil 172 }