go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/culpritverification/test_failure_verify_culprit_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 culpritverification performs culprit verification for test failures.
    16  package culpritverification
    17  
    18  import (
    19  	"context"
    20  	"encoding/json"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	. "github.com/smartystreets/goconvey/convey"
    26  	"go.chromium.org/luci/bisection/internal/buildbucket"
    27  	"go.chromium.org/luci/bisection/internal/config"
    28  	"go.chromium.org/luci/bisection/internal/gitiles"
    29  	"go.chromium.org/luci/bisection/model"
    30  	configpb "go.chromium.org/luci/bisection/proto/config"
    31  	pb "go.chromium.org/luci/bisection/proto/v1"
    32  	tpb "go.chromium.org/luci/bisection/task/proto"
    33  	"go.chromium.org/luci/bisection/util/testutil"
    34  	bbpb "go.chromium.org/luci/buildbucket/proto"
    35  	"go.chromium.org/luci/common/clock"
    36  	"go.chromium.org/luci/common/clock/testclock"
    37  	. "go.chromium.org/luci/common/testing/assertions"
    38  	"go.chromium.org/luci/gae/impl/memory"
    39  	"go.chromium.org/luci/gae/service/datastore"
    40  )
    41  
    42  func TestProcessTestFailureTask(t *testing.T) {
    43  	t.Parallel()
    44  	c := context.Background()
    45  	cl := testclock.New(testclock.TestTimeUTC)
    46  	c = clock.Set(c, cl)
    47  
    48  	// Setup mock for buildbucket
    49  	ctl := gomock.NewController(t)
    50  	defer ctl.Finish()
    51  	mc := buildbucket.NewMockedClient(c, ctl)
    52  	c = mc.Ctx
    53  	build1 := buildbucket.MockScheduleBuild(mc, 123, "3425")
    54  	build2 := buildbucket.MockScheduleBuild(mc, 456, "3424")
    55  	buildbucket.MockGetBuild(mc)
    56  
    57  	Convey("process test failure task", t, func() {
    58  		c = memory.Use(c)
    59  		testutil.UpdateIndices(c)
    60  
    61  		// Setup config.
    62  		projectCfg := config.CreatePlaceholderProjectConfig()
    63  		cfg := map[string]*configpb.ProjectConfig{"chromium": projectCfg}
    64  		So(config.SetTestProjectConfig(c, cfg), ShouldBeNil)
    65  
    66  		Convey("trigger rerun", func() {
    67  			tfa := testutil.CreateTestFailureAnalysis(c, nil)
    68  			nsa := testutil.CreateTestNthSectionAnalysis(c, &testutil.TestNthSectionAnalysisCreationOption{
    69  				ParentAnalysisKey: datastore.KeyForObj(c, tfa),
    70  			})
    71  			suspect := testutil.CreateSuspect(c, &testutil.SuspectCreationOption{
    72  				ParentKey: datastore.KeyForObj(c, nsa),
    73  				CommitID:  "3425",
    74  			})
    75  			tf := testutil.CreateTestFailure(c, &testutil.TestFailureCreationOption{IsPrimary: true, Analysis: tfa})
    76  			gitilesResponse := model.ChangeLogResponse{
    77  				Log: []*model.ChangeLog{
    78  					{
    79  						Commit: "3424",
    80  					},
    81  				},
    82  			}
    83  			gitilesResponseStr, _ := json.Marshal(gitilesResponse)
    84  			c = gitiles.MockedGitilesClientContext(c, map[string]string{
    85  				"https://chromium.googlesource.com/chromium/src/+log/3425~2..3425^": string(gitilesResponseStr),
    86  			})
    87  			task := &tpb.TestFailureCulpritVerificationTask{
    88  				AnalysisId: tfa.ID,
    89  			}
    90  
    91  			err := processTestFailureTask(c, task)
    92  			So(err, ShouldBeNil)
    93  			datastore.GetTestable(c).CatchupIndexes()
    94  			// Check suspect updated.
    95  			So(datastore.Get(c, suspect), ShouldBeNil)
    96  			So(suspect.VerificationStatus, ShouldEqual, model.SuspectVerificationStatus_UnderVerification)
    97  			// Check rerun saved.
    98  			suspectRerun := &model.TestSingleRerun{
    99  				ID: suspect.SuspectRerunBuild.IntID(),
   100  			}
   101  			err = datastore.Get(c, suspectRerun)
   102  			So(err, ShouldBeNil)
   103  			expectedRerun := &model.TestSingleRerun{
   104  				ID: build1.Id,
   105  				LUCIBuild: model.LUCIBuild{
   106  					BuildID:       build1.Id,
   107  					Project:       build1.Builder.Project,
   108  					Bucket:        build1.Builder.Bucket,
   109  					Builder:       build1.Builder.Builder,
   110  					GitilesCommit: build1.Input.GitilesCommit,
   111  					CreateTime:    build1.CreateTime.AsTime(),
   112  					EndTime:       time.Time{},
   113  					StartTime:     build1.StartTime.AsTime(),
   114  					Status:        bbpb.Status_STARTED,
   115  				},
   116  				Type:        model.RerunBuildType_CulpritVerification,
   117  				AnalysisKey: datastore.KeyForObj(c, tfa),
   118  				CulpritKey:  datastore.KeyForObj(c, suspect),
   119  				TestResults: model.RerunTestResults{
   120  					IsFinalized: false,
   121  					Results: []model.RerunSingleTestResult{{
   122  						TestFailureKey: datastore.KeyForObj(c, tf),
   123  					}},
   124  				},
   125  				Dimensions: &pb.Dimensions{},
   126  				Status:     pb.RerunStatus_RERUN_STATUS_IN_PROGRESS,
   127  			}
   128  			So(suspectRerun, ShouldResembleProto, expectedRerun)
   129  			parentRerun := &model.TestSingleRerun{
   130  				ID: suspect.ParentRerunBuild.IntID(),
   131  			}
   132  			err = datastore.Get(c, parentRerun)
   133  			So(err, ShouldBeNil)
   134  			expectedRerun.ID = build2.Id
   135  			expectedRerun.LUCIBuild.BuildID = build2.Id
   136  			expectedRerun.LUCIBuild.GitilesCommit = build2.Input.GitilesCommit
   137  			So(parentRerun, ShouldResembleProto, expectedRerun)
   138  		})
   139  	})
   140  
   141  }