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  }