go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/util/testutil/testutil.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 testutil contains utility functions for test.
    16  package testutil
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"time"
    22  
    23  	. "github.com/smartystreets/goconvey/convey"
    24  	"google.golang.org/protobuf/types/known/timestamppb"
    25  
    26  	"go.chromium.org/luci/bisection/model"
    27  	pb "go.chromium.org/luci/bisection/proto/v1"
    28  	bbpb "go.chromium.org/luci/buildbucket/proto"
    29  	"go.chromium.org/luci/gae/service/datastore"
    30  )
    31  
    32  func CreateBlamelist(nCommits int) *pb.BlameList {
    33  	blamelist := &pb.BlameList{}
    34  	for i := 0; i < nCommits; i++ {
    35  		blamelist.Commits = append(blamelist.Commits, &pb.BlameListSingleCommit{
    36  			Commit:     fmt.Sprintf("commit%d", i),
    37  			CommitTime: timestamppb.New(time.Unix(int64(i+1000), 0)),
    38  		})
    39  	}
    40  	blamelist.LastPassCommit = &pb.BlameListSingleCommit{
    41  		Commit: fmt.Sprintf("commit%d", nCommits),
    42  	}
    43  	return blamelist
    44  }
    45  
    46  func CreateLUCIFailedBuild(c context.Context, id int64, project string) *model.LuciFailedBuild {
    47  	fb := &model.LuciFailedBuild{
    48  		Id: id,
    49  		LuciBuild: model.LuciBuild{
    50  			Project: project,
    51  		},
    52  		SheriffRotations: []string{"chromium"},
    53  	}
    54  	So(datastore.Put(c, fb), ShouldBeNil)
    55  	datastore.GetTestable(c).CatchupIndexes()
    56  	return fb
    57  }
    58  
    59  func CreateCompileFailure(c context.Context, fb *model.LuciFailedBuild) *model.CompileFailure {
    60  	cf := &model.CompileFailure{
    61  		Id:    fb.Id,
    62  		Build: datastore.KeyForObj(c, fb),
    63  	}
    64  	So(datastore.Put(c, cf), ShouldBeNil)
    65  	datastore.GetTestable(c).CatchupIndexes()
    66  	return cf
    67  }
    68  
    69  func CreateCompileFailureAnalysis(c context.Context, id int64, cf *model.CompileFailure) *model.CompileFailureAnalysis {
    70  	cfa := &model.CompileFailureAnalysis{
    71  		Id:             id,
    72  		CompileFailure: datastore.KeyForObj(c, cf),
    73  	}
    74  	So(datastore.Put(c, cfa), ShouldBeNil)
    75  	datastore.GetTestable(c).CatchupIndexes()
    76  	return cfa
    77  }
    78  
    79  func CreateCompileFailureAnalysisAnalysisChain(c context.Context, bbid int64, project string, analysisID int64) (*model.LuciFailedBuild, *model.CompileFailure, *model.CompileFailureAnalysis) {
    80  	fb := CreateLUCIFailedBuild(c, bbid, project)
    81  	cf := CreateCompileFailure(c, fb)
    82  	cfa := CreateCompileFailureAnalysis(c, analysisID, cf)
    83  	return fb, cf, cfa
    84  }
    85  
    86  func CreateHeuristicAnalysis(c context.Context, cfa *model.CompileFailureAnalysis) *model.CompileHeuristicAnalysis {
    87  	ha := &model.CompileHeuristicAnalysis{
    88  		ParentAnalysis: datastore.KeyForObj(c, cfa),
    89  	}
    90  	So(datastore.Put(c, ha), ShouldBeNil)
    91  	datastore.GetTestable(c).CatchupIndexes()
    92  	return ha
    93  }
    94  
    95  func CreateNthSectionAnalysis(c context.Context, cfa *model.CompileFailureAnalysis) *model.CompileNthSectionAnalysis {
    96  	nsa := &model.CompileNthSectionAnalysis{
    97  		ParentAnalysis: datastore.KeyForObj(c, cfa),
    98  	}
    99  	So(datastore.Put(c, nsa), ShouldBeNil)
   100  	datastore.GetTestable(c).CatchupIndexes()
   101  	return nsa
   102  }
   103  
   104  func CreateHeuristicSuspect(c context.Context, ha *model.CompileHeuristicAnalysis, status model.SuspectVerificationStatus) *model.Suspect {
   105  	suspect := &model.Suspect{
   106  		ParentAnalysis:     datastore.KeyForObj(c, ha),
   107  		Type:               model.SuspectType_Heuristic,
   108  		VerificationStatus: status,
   109  	}
   110  	So(datastore.Put(c, suspect), ShouldBeNil)
   111  	datastore.GetTestable(c).CatchupIndexes()
   112  	return suspect
   113  }
   114  
   115  func CreateNthSectionSuspect(c context.Context, nsa *model.CompileNthSectionAnalysis) *model.Suspect {
   116  	suspect := &model.Suspect{
   117  		ParentAnalysis: datastore.KeyForObj(c, nsa),
   118  		Type:           model.SuspectType_NthSection,
   119  	}
   120  	So(datastore.Put(c, suspect), ShouldBeNil)
   121  	datastore.GetTestable(c).CatchupIndexes()
   122  	return suspect
   123  }
   124  
   125  type TestFailureCreationOption struct {
   126  	ID               int64
   127  	Project          string
   128  	Variant          map[string]string
   129  	IsPrimary        bool
   130  	Analysis         *model.TestFailureAnalysis
   131  	Ref              *pb.SourceRef
   132  	TestID           string
   133  	VariantHash      string
   134  	StartHour        time.Time
   135  	RefHash          string
   136  	StartPosition    int64
   137  	EndPosition      int64
   138  	StartFailureRate float64
   139  	EndFailureRate   float64
   140  	IsDiverged       bool
   141  }
   142  
   143  func CreateTestFailure(ctx context.Context, option *TestFailureCreationOption) *model.TestFailure {
   144  	id := int64(100)
   145  	project := "chromium"
   146  	variant := map[string]string{}
   147  	isPrimary := false
   148  	var analysisKey *datastore.Key = nil
   149  	var ref *pb.SourceRef = nil
   150  	var testID = ""
   151  	var variantHash = ""
   152  	var startHour time.Time
   153  	var refHash = ""
   154  	var startPosition int64
   155  	var endPosition int64
   156  	var startFailureRate float64
   157  	var endFailureRate float64
   158  	var isDiverged bool
   159  
   160  	if option != nil {
   161  		if option.ID != 0 {
   162  			id = option.ID
   163  		}
   164  		if option.Project != "" {
   165  			project = option.Project
   166  		}
   167  		if option.Analysis != nil {
   168  			analysisKey = datastore.KeyForObj(ctx, option.Analysis)
   169  		}
   170  		variant = option.Variant
   171  		isPrimary = option.IsPrimary
   172  		ref = option.Ref
   173  		testID = option.TestID
   174  		variantHash = option.VariantHash
   175  		startHour = option.StartHour
   176  		refHash = option.RefHash
   177  		startPosition = option.StartPosition
   178  		endPosition = option.EndPosition
   179  		startFailureRate = option.StartFailureRate
   180  		endFailureRate = option.EndFailureRate
   181  		isDiverged = option.IsDiverged
   182  	}
   183  
   184  	tf := &model.TestFailure{
   185  		ID:      id,
   186  		Project: project,
   187  		Variant: &pb.Variant{
   188  			Def: variant,
   189  		},
   190  		IsPrimary:                isPrimary,
   191  		AnalysisKey:              analysisKey,
   192  		Ref:                      ref,
   193  		TestID:                   testID,
   194  		VariantHash:              variantHash,
   195  		StartHour:                startHour,
   196  		RefHash:                  refHash,
   197  		RegressionStartPosition:  startPosition,
   198  		RegressionEndPosition:    endPosition,
   199  		StartPositionFailureRate: startFailureRate,
   200  		EndPositionFailureRate:   endFailureRate,
   201  		IsDiverged:               isDiverged,
   202  	}
   203  
   204  	So(datastore.Put(ctx, tf), ShouldBeNil)
   205  	datastore.GetTestable(ctx).CatchupIndexes()
   206  	return tf
   207  }
   208  
   209  type TestFailureAnalysisCreationOption struct {
   210  	ID                 int64
   211  	Project            string
   212  	Bucket             string
   213  	Builder            string
   214  	TestFailureKey     *datastore.Key
   215  	StartCommitHash    string
   216  	EndCommitHash      string
   217  	FailedBuildID      int64
   218  	Priority           int32
   219  	Status             pb.AnalysisStatus
   220  	RunStatus          pb.AnalysisRunStatus
   221  	CreateTime         time.Time
   222  	StartTime          time.Time
   223  	EndTime            time.Time
   224  	VerifiedCulpritKey *datastore.Key
   225  }
   226  
   227  func CreateTestFailureAnalysis(ctx context.Context, option *TestFailureAnalysisCreationOption) *model.TestFailureAnalysis {
   228  	id := int64(1000)
   229  	project := "chromium"
   230  	bucket := "bucket"
   231  	builder := "builder"
   232  	var tfKey *datastore.Key = nil
   233  	startCommitHash := ""
   234  	endCommitHash := ""
   235  	failedBuildID := int64(8000)
   236  	var priority int32
   237  	var status pb.AnalysisStatus
   238  	var runStatus pb.AnalysisRunStatus
   239  	var createTime time.Time
   240  	var startTime time.Time
   241  	var endTime time.Time
   242  	var verifiedCulpritKey *datastore.Key = nil
   243  
   244  	if option != nil {
   245  		if option.ID != 0 {
   246  			id = option.ID
   247  		}
   248  		if option.Project != "" {
   249  			project = option.Project
   250  		}
   251  		if option.Bucket != "" {
   252  			bucket = option.Bucket
   253  		}
   254  		if option.Builder != "" {
   255  			builder = option.Builder
   256  		}
   257  		if option.StartCommitHash != "" {
   258  			startCommitHash = option.StartCommitHash
   259  		}
   260  		if option.EndCommitHash != "" {
   261  			endCommitHash = option.EndCommitHash
   262  		}
   263  		if option.FailedBuildID != 0 {
   264  			failedBuildID = option.FailedBuildID
   265  		}
   266  		priority = option.Priority
   267  		tfKey = option.TestFailureKey
   268  		status = option.Status
   269  		runStatus = option.RunStatus
   270  		createTime = option.CreateTime
   271  		startTime = option.StartTime
   272  		endTime = option.EndTime
   273  		verifiedCulpritKey = option.VerifiedCulpritKey
   274  	}
   275  
   276  	tfa := &model.TestFailureAnalysis{
   277  		ID:                 id,
   278  		Project:            project,
   279  		Bucket:             bucket,
   280  		Builder:            builder,
   281  		TestFailure:        tfKey,
   282  		StartCommitHash:    startCommitHash,
   283  		EndCommitHash:      endCommitHash,
   284  		FailedBuildID:      failedBuildID,
   285  		Priority:           int32(priority),
   286  		Status:             status,
   287  		RunStatus:          runStatus,
   288  		CreateTime:         createTime,
   289  		StartTime:          startTime,
   290  		EndTime:            endTime,
   291  		VerifiedCulpritKey: verifiedCulpritKey,
   292  	}
   293  	So(datastore.Put(ctx, tfa), ShouldBeNil)
   294  	datastore.GetTestable(ctx).CatchupIndexes()
   295  	return tfa
   296  }
   297  
   298  type TestSingleRerunCreationOption struct {
   299  	ID                    int64
   300  	Status                pb.RerunStatus
   301  	AnalysisKey           *datastore.Key
   302  	Type                  model.RerunBuildType
   303  	TestResult            model.RerunTestResults
   304  	NthSectionAnalysisKey *datastore.Key
   305  	CulpritKey            *datastore.Key
   306  	CreateTime            time.Time
   307  	StartTime             time.Time
   308  	ReportTime            time.Time
   309  	EndTime               time.Time
   310  	BuildStatus           bbpb.Status
   311  	GitilesCommit         *bbpb.GitilesCommit
   312  }
   313  
   314  func CreateTestSingleRerun(ctx context.Context, option *TestSingleRerunCreationOption) *model.TestSingleRerun {
   315  	id := int64(1000)
   316  	status := pb.RerunStatus_RERUN_STATUS_UNSPECIFIED
   317  	var analysisKey *datastore.Key
   318  	var rerunType model.RerunBuildType
   319  	testresult := model.RerunTestResults{}
   320  	var nthSectionAnalysisKey *datastore.Key
   321  	var culpritKey *datastore.Key
   322  	var startTime time.Time
   323  	var createTime time.Time
   324  	var reportTime time.Time
   325  	var endTime time.Time
   326  	var buildStatus bbpb.Status
   327  	var gitilesCommit *bbpb.GitilesCommit
   328  
   329  	if option != nil {
   330  		if option.ID != 0 {
   331  			id = option.ID
   332  		}
   333  		status = option.Status
   334  		analysisKey = option.AnalysisKey
   335  		rerunType = option.Type
   336  		testresult = option.TestResult
   337  		nthSectionAnalysisKey = option.NthSectionAnalysisKey
   338  		culpritKey = option.CulpritKey
   339  		startTime = option.StartTime
   340  		createTime = option.CreateTime
   341  		reportTime = option.ReportTime
   342  		endTime = option.EndTime
   343  		buildStatus = option.BuildStatus
   344  		gitilesCommit = option.GitilesCommit
   345  	}
   346  	rerun := &model.TestSingleRerun{
   347  		ID:                    id,
   348  		Status:                status,
   349  		AnalysisKey:           analysisKey,
   350  		Type:                  rerunType,
   351  		TestResults:           testresult,
   352  		NthSectionAnalysisKey: nthSectionAnalysisKey,
   353  		CulpritKey:            culpritKey,
   354  		ReportTime:            reportTime,
   355  		LUCIBuild: model.LUCIBuild{
   356  			CreateTime:    createTime,
   357  			StartTime:     startTime,
   358  			EndTime:       endTime,
   359  			Status:        buildStatus,
   360  			GitilesCommit: gitilesCommit,
   361  		},
   362  	}
   363  	So(datastore.Put(ctx, rerun), ShouldBeNil)
   364  	datastore.GetTestable(ctx).CatchupIndexes()
   365  	return rerun
   366  }
   367  
   368  type TestNthSectionAnalysisCreationOption struct {
   369  	ID                int64
   370  	ParentAnalysisKey *datastore.Key
   371  	BlameList         *pb.BlameList
   372  	Status            pb.AnalysisStatus
   373  	RunStatus         pb.AnalysisRunStatus
   374  	StartTime         time.Time
   375  	EndTime           time.Time
   376  	CulpritKey        *datastore.Key
   377  }
   378  
   379  func CreateTestNthSectionAnalysis(ctx context.Context, option *TestNthSectionAnalysisCreationOption) *model.TestNthSectionAnalysis {
   380  	id := int64(1000)
   381  	var parentAnalysis *datastore.Key = nil
   382  	var blameList *pb.BlameList
   383  	var status pb.AnalysisStatus
   384  	var runStatus pb.AnalysisRunStatus
   385  	var startTime time.Time
   386  	var endTime time.Time
   387  	var culpritKey *datastore.Key
   388  
   389  	if option != nil {
   390  		if option.ID != 0 {
   391  			id = option.ID
   392  		}
   393  		parentAnalysis = option.ParentAnalysisKey
   394  		blameList = option.BlameList
   395  		status = option.Status
   396  		runStatus = option.RunStatus
   397  		startTime = option.StartTime
   398  		endTime = option.EndTime
   399  		culpritKey = option.CulpritKey
   400  	}
   401  	nsa := &model.TestNthSectionAnalysis{
   402  		ID:                id,
   403  		ParentAnalysisKey: parentAnalysis,
   404  		BlameList:         blameList,
   405  		Status:            status,
   406  		RunStatus:         runStatus,
   407  		StartTime:         startTime,
   408  		EndTime:           endTime,
   409  		CulpritKey:        culpritKey,
   410  	}
   411  	So(datastore.Put(ctx, nsa), ShouldBeNil)
   412  	datastore.GetTestable(ctx).CatchupIndexes()
   413  	return nsa
   414  }
   415  
   416  type SuspectCreationOption struct {
   417  	ID                 int64
   418  	ParentKey          *datastore.Key
   419  	CommitID           string
   420  	ReviewURL          string
   421  	ReviewTitle        string
   422  	SuspectRerunKey    *datastore.Key
   423  	ParentRerunKey     *datastore.Key
   424  	VerificationStatus model.SuspectVerificationStatus
   425  	ActionDetails      model.ActionDetails
   426  	AnalysisType       pb.AnalysisType
   427  }
   428  
   429  func CreateSuspect(ctx context.Context, option *SuspectCreationOption) *model.Suspect {
   430  	var parentKey *datastore.Key
   431  	id := int64(500)
   432  	commitID := "1"
   433  	reviewURL := ""
   434  	reviewTitle := ""
   435  	var suspectRerunKey *datastore.Key
   436  	var parentRerunKey *datastore.Key
   437  	var verificationStatus model.SuspectVerificationStatus
   438  	var actionDetails model.ActionDetails
   439  	var analysisType pb.AnalysisType
   440  
   441  	if option != nil {
   442  		if option.ID != 0 {
   443  			id = option.ID
   444  		}
   445  		if option.CommitID != "" {
   446  			commitID = option.CommitID
   447  		}
   448  		parentKey = option.ParentKey
   449  		reviewURL = option.ReviewURL
   450  		reviewTitle = option.ReviewTitle
   451  		suspectRerunKey = option.SuspectRerunKey
   452  		parentRerunKey = option.ParentRerunKey
   453  		verificationStatus = option.VerificationStatus
   454  		actionDetails = option.ActionDetails
   455  		analysisType = option.AnalysisType
   456  	}
   457  	suspect := &model.Suspect{
   458  		Id:             id,
   459  		ParentAnalysis: parentKey,
   460  		GitilesCommit: bbpb.GitilesCommit{
   461  			Host:    "chromium.googlesource.com",
   462  			Project: "chromium/src",
   463  			Ref:     "ref",
   464  			Id:      commitID,
   465  		},
   466  		ReviewUrl:          reviewURL,
   467  		ReviewTitle:        reviewTitle,
   468  		SuspectRerunBuild:  suspectRerunKey,
   469  		ParentRerunBuild:   parentRerunKey,
   470  		VerificationStatus: verificationStatus,
   471  		ActionDetails:      actionDetails,
   472  		AnalysisType:       analysisType,
   473  	}
   474  	So(datastore.Put(ctx, suspect), ShouldBeNil)
   475  	datastore.GetTestable(ctx).CatchupIndexes()
   476  	return suspect
   477  }
   478  
   479  func UpdateIndices(c context.Context) {
   480  	datastore.GetTestable(c).AddIndexes(
   481  		&datastore.IndexDefinition{
   482  			Kind: "SingleRerun",
   483  			SortBy: []datastore.IndexColumn{
   484  				{
   485  					Property: "analysis",
   486  				},
   487  				{
   488  					Property: "start_time",
   489  				},
   490  			},
   491  		},
   492  		&datastore.IndexDefinition{
   493  			Kind: "Suspect",
   494  			SortBy: []datastore.IndexColumn{
   495  				{
   496  					Property: "analysis_type",
   497  				},
   498  				{
   499  					Property: "is_revert_created",
   500  				},
   501  				{
   502  					Property: "revert_create_time",
   503  				},
   504  			},
   505  		},
   506  		&datastore.IndexDefinition{
   507  			Kind: "Suspect",
   508  			SortBy: []datastore.IndexColumn{
   509  				{
   510  					Property: "is_revert_committed",
   511  				},
   512  				{
   513  					Property: "revert_commit_time",
   514  				},
   515  			},
   516  		},
   517  		&datastore.IndexDefinition{
   518  			Kind: "SingleRerun",
   519  			SortBy: []datastore.IndexColumn{
   520  				{
   521  					Property: "rerun_build",
   522  				},
   523  				{
   524  					Property: "start_time",
   525  				},
   526  			},
   527  		},
   528  		&datastore.IndexDefinition{
   529  			Kind: "SingleRerun",
   530  			SortBy: []datastore.IndexColumn{
   531  				{
   532  					Property: "Status",
   533  				},
   534  				{
   535  					Property: "create_time",
   536  				},
   537  			},
   538  		},
   539  		&datastore.IndexDefinition{
   540  			Kind: "LuciFailedBuild",
   541  			SortBy: []datastore.IndexColumn{
   542  				{
   543  					Property: "project",
   544  				},
   545  				{
   546  					Property: "bucket",
   547  				},
   548  				{
   549  					Property: "builder",
   550  				},
   551  				{
   552  					Property:   "end_time",
   553  					Descending: true,
   554  				},
   555  			},
   556  		},
   557  		&datastore.IndexDefinition{
   558  			Kind: "TestSingleRerun",
   559  			SortBy: []datastore.IndexColumn{
   560  				{
   561  					Property: "nthsection_analysis_key",
   562  				},
   563  				{
   564  					Property: "luci_build.create_time",
   565  				},
   566  			},
   567  		},
   568  		&datastore.IndexDefinition{
   569  			Kind: "CompileRerunBuild",
   570  			SortBy: []datastore.IndexColumn{
   571  				{
   572  					Property: "project",
   573  				},
   574  				{
   575  					Property: "status",
   576  				},
   577  				{
   578  					Property: "create_time",
   579  				},
   580  			},
   581  		},
   582  		&datastore.IndexDefinition{
   583  			Kind: "TestSingleRerun",
   584  			SortBy: []datastore.IndexColumn{
   585  				{
   586  					Property: "luci_build.project",
   587  				},
   588  				{
   589  					Property: "luci_build.status",
   590  				},
   591  				{
   592  					Property: "luci_build.create_time",
   593  				},
   594  			},
   595  		},
   596  		&datastore.IndexDefinition{
   597  			Kind: "TestSingleRerun",
   598  			SortBy: []datastore.IndexColumn{
   599  				{
   600  					Property: "status",
   601  				},
   602  				{
   603  					Property: "luci_build.create_time",
   604  				},
   605  			},
   606  		},
   607  		&datastore.IndexDefinition{
   608  			Kind: "TestFailureAnalysis",
   609  			SortBy: []datastore.IndexColumn{
   610  				{
   611  					Property: "project",
   612  				},
   613  				{
   614  					Property: "create_time",
   615  				},
   616  			},
   617  		},
   618  		&datastore.IndexDefinition{
   619  			Kind: "TestFailureAnalysis",
   620  			SortBy: []datastore.IndexColumn{
   621  				{
   622  					Property: "project",
   623  				},
   624  				{
   625  					Property:   "create_time",
   626  					Descending: true,
   627  				},
   628  			},
   629  		},
   630  	)
   631  	datastore.GetTestable(c).CatchupIndexes()
   632  }