go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/ingestion/join/build_test.go (about) 1 // Copyright 2022 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 join 16 17 import ( 18 "fmt" 19 "testing" 20 "time" 21 22 "github.com/golang/mock/gomock" 23 "google.golang.org/protobuf/types/known/timestamppb" 24 25 resultpb "go.chromium.org/luci/resultdb/proto/v1" 26 "go.chromium.org/luci/server/tq" 27 28 controlpb "go.chromium.org/luci/analysis/internal/ingestion/control/proto" 29 "go.chromium.org/luci/analysis/internal/resultdb" 30 "go.chromium.org/luci/analysis/internal/tasks/taskspb" 31 "go.chromium.org/luci/analysis/internal/testutil" 32 pb "go.chromium.org/luci/analysis/proto/v1" 33 34 _ "go.chromium.org/luci/analysis/internal/services/resultingester" // Needed to ensure task class is registered. 35 36 . "github.com/smartystreets/goconvey/convey" 37 . "go.chromium.org/luci/common/testing/assertions" 38 ) 39 40 func TestHandleBuild(t *testing.T) { 41 Convey(`Test JoinBuild`, t, func() { 42 ctx := testutil.IntegrationTestContext(t) 43 ctx, skdr := tq.TestingContext(ctx, nil) 44 45 createTime := time.Now() 46 47 build := newBuildBuilder(14141414). 48 WithCreateTime(createTime) 49 50 expectedTask := &taskspb.IngestTestResults{ 51 PartitionTime: timestamppb.New(createTime), 52 Build: build.ExpectedResult(), 53 } 54 55 assertTasksExpected := func() { 56 So(len(skdr.Tasks().Payloads()), ShouldEqual, 1) 57 resultsTask := skdr.Tasks().Payloads()[0].(*taskspb.IngestTestResults) 58 So(resultsTask, ShouldResembleProto, expectedTask) 59 } 60 61 Convey(`With vanilla build`, func() { 62 Convey(`Vanilla CI Build`, func() { 63 build = build.WithGardenerRotations([]string{"rotation1", "rotation2"}) 64 65 // Process build. 66 So(ingestBuild(ctx, build), ShouldBeNil) 67 68 assertTasksExpected() 69 70 // Test repeated processing does not lead to further 71 // ingestion tasks. 72 So(ingestBuild(ctx, build), ShouldBeNil) 73 74 assertTasksExpected() 75 }) 76 Convey(`Unusual CI Build`, func() { 77 // v8 project had some buildbucket-triggered builds 78 // with both the user_agent:cq and user_agent:recipe tags. 79 // These should be treated as CI builds. 80 build = build.WithTags([]string{"user_agent:cq", "user_agent:recipe"}) 81 expectedTask.Build = build.ExpectedResult() 82 83 // Process build. 84 So(ingestBuild(ctx, build), ShouldBeNil) 85 assertTasksExpected() 86 }) 87 }) 88 Convey(`With ancestor build`, func() { 89 build = build.WithAncestorIDs([]int64{01010101, 57575757}) 90 expectedTask.Build = build.ExpectedResult() 91 92 ctl := gomock.NewController(t) 93 defer ctl.Finish() 94 95 mrc := resultdb.NewMockedClient(ctx, ctl) 96 ctx := mrc.Ctx 97 98 Convey(`Without invocation`, func() { 99 build = build.WithContainedByAncestor(false) 100 expectedTask.Build = build.ExpectedResult() 101 102 // Process build. 103 So(ingestBuild(ctx, build), ShouldBeNil) 104 assertTasksExpected() 105 }) 106 Convey(`With invocation`, func() { 107 So(ingestFinalization(ctx, build.buildID), ShouldBeNil) 108 So(len(skdr.Tasks().Payloads()), ShouldEqual, 0) 109 110 Convey(`Not contained by ancestor`, func() { 111 build = build.WithInvocation().WithContainedByAncestor(false) 112 expectedTask.Build = build.ExpectedResult() 113 114 req := &resultpb.GetInvocationRequest{ 115 Name: "invocations/build-57575757", 116 } 117 res := &resultpb.Invocation{ 118 Name: "invocations/build-57575757", 119 IncludedInvocations: []string{"invocations/build-unrelated"}, 120 } 121 mrc.GetInvocation(req, res) 122 123 // Process build. 124 So(ingestBuild(ctx, build), ShouldBeNil) 125 assertTasksExpected() 126 }) 127 Convey(`Contained by ancestor`, func() { 128 build = build.WithInvocation().WithContainedByAncestor(true) 129 expectedTask.Build = build.ExpectedResult() 130 131 req := &resultpb.GetInvocationRequest{ 132 Name: "invocations/build-57575757", 133 } 134 res := &resultpb.Invocation{ 135 Name: "invocations/build-57575757", 136 IncludedInvocations: []string{ 137 "invocations/build-unrelated", 138 fmt.Sprintf("invocations/build-%v", build.buildID), 139 }, 140 } 141 mrc.GetInvocation(req, res) 142 143 // Process build. 144 So(ingestBuild(ctx, build), ShouldBeNil) 145 assertTasksExpected() 146 }) 147 }) 148 }) 149 Convey(`With build that is part of a LUCI CV run`, func() { 150 build := build.WithTags([]string{"user_agent:cq"}) 151 expectedTask.Build = build.ExpectedResult() 152 153 Convey(`Without LUCI CV run processed previously`, func() { 154 So(ingestBuild(ctx, build), ShouldBeNil) 155 156 So(len(skdr.Tasks().Payloads()), ShouldEqual, 0) 157 }) 158 Convey(`With LUCI CV run processed previously`, func() { 159 So(ingestCVRun(ctx, []int64{11111171, build.buildID}), ShouldBeNil) 160 161 So(len(skdr.Tasks().Payloads()), ShouldEqual, 0) 162 163 So(ingestBuild(ctx, build), ShouldBeNil) 164 165 expectedTask.PartitionTime = timestamppb.New(cvCreateTime) 166 expectedTask.PresubmitRun = &controlpb.PresubmitResult{ 167 PresubmitRunId: &pb.PresubmitRunId{ 168 System: "luci-cv", 169 Id: "cvproject/123e4567-e89b-12d3-a456-426614174000", 170 }, 171 Status: pb.PresubmitRunStatus_PRESUBMIT_RUN_STATUS_FAILED, 172 Owner: "automation", 173 Mode: pb.PresubmitRunMode_FULL_RUN, 174 CreationTime: timestamppb.New(cvCreateTime), 175 Critical: true, 176 } 177 assertTasksExpected() 178 179 // Check metrics were reported correctly for this sequence. 180 isPresubmit := true 181 hasInvocation := false 182 So(bbBuildInputCounter.Get(ctx, "buildproject", isPresubmit, hasInvocation), ShouldEqual, 1) 183 So(bbBuildOutputCounter.Get(ctx, "buildproject", isPresubmit, hasInvocation), ShouldEqual, 1) 184 So(cvBuildInputCounter.Get(ctx, "cvproject"), ShouldEqual, 2) 185 So(cvBuildOutputCounter.Get(ctx, "cvproject"), ShouldEqual, 1) 186 So(rdbBuildInputCounter.Get(ctx, "invproject"), ShouldEqual, 0) 187 So(rdbBuildOutputCounter.Get(ctx, "invproject"), ShouldEqual, 0) 188 }) 189 }) 190 Convey(`With build that has a ResultDB invocation`, func() { 191 build := build.WithInvocation() 192 expectedTask.Build = build.ExpectedResult() 193 194 Convey(`Without invocation finalization acknowledged previously`, func() { 195 So(ingestBuild(ctx, build), ShouldBeNil) 196 197 So(len(skdr.Tasks().Payloads()), ShouldEqual, 0) 198 }) 199 Convey(`With invocation finalization acknowledged previously`, func() { 200 So(ingestFinalization(ctx, build.buildID), ShouldBeNil) 201 202 So(len(skdr.Tasks().Payloads()), ShouldEqual, 0) 203 204 So(ingestBuild(ctx, build), ShouldBeNil) 205 206 assertTasksExpected() 207 208 // Check metrics were reported correctly for this sequence. 209 isPresubmit := false 210 hasInvocation := true 211 So(bbBuildInputCounter.Get(ctx, "buildproject", isPresubmit, hasInvocation), ShouldEqual, 1) 212 So(bbBuildOutputCounter.Get(ctx, "buildproject", isPresubmit, hasInvocation), ShouldEqual, 1) 213 So(cvBuildInputCounter.Get(ctx, "cvproject"), ShouldEqual, 0) 214 So(cvBuildOutputCounter.Get(ctx, "cvproject"), ShouldEqual, 0) 215 So(rdbBuildInputCounter.Get(ctx, "invproject"), ShouldEqual, 1) 216 So(rdbBuildOutputCounter.Get(ctx, "invproject"), ShouldEqual, 1) 217 }) 218 }) 219 }) 220 }