go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/ingestion/control/testutils.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 control
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"cloud.google.com/go/spanner"
    24  	"google.golang.org/protobuf/types/known/timestamppb"
    25  
    26  	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
    27  	"go.chromium.org/luci/server/span"
    28  
    29  	controlpb "go.chromium.org/luci/analysis/internal/ingestion/control/proto"
    30  	spanutil "go.chromium.org/luci/analysis/internal/span"
    31  	"go.chromium.org/luci/analysis/internal/testutil"
    32  	pb "go.chromium.org/luci/analysis/proto/v1"
    33  )
    34  
    35  // EntryBuilder provides methods to build ingestion control records.
    36  type EntryBuilder struct {
    37  	record *Entry
    38  }
    39  
    40  // NewEntry starts building a new Entry.
    41  func NewEntry(uniqifier int) *EntryBuilder {
    42  	return &EntryBuilder{
    43  		record: &Entry{
    44  			BuildID:      fmt.Sprintf("buildbucket-host/%v", uniqifier),
    45  			BuildProject: "build-project",
    46  			BuildResult: &controlpb.BuildResult{
    47  				Host:         "buildbucket-host",
    48  				Id:           int64(uniqifier),
    49  				CreationTime: timestamppb.New(time.Date(2025, time.December, 1, 1, 2, 3, uniqifier*1000, time.UTC)),
    50  				Project:      "myproject",
    51  				Builder:      "builder",
    52  				Status:       pb.BuildStatus_BUILD_STATUS_SUCCESS,
    53  				Changelists: []*pb.Changelist{
    54  					{
    55  						Host:      "myhost-review.googlesource.com",
    56  						Change:    123456,
    57  						Patchset:  123,
    58  						OwnerKind: pb.ChangelistOwnerKind_AUTOMATION,
    59  					},
    60  				},
    61  				Commit: &buildbucketpb.GitilesCommit{
    62  					Host:     "myproject.googlesource.com",
    63  					Project:  "someproject/src",
    64  					Id:       strings.Repeat("0a", 20),
    65  					Ref:      "refs/heads/mybranch",
    66  					Position: 111888,
    67  				},
    68  				HasInvocation:        true,
    69  				ResultdbHost:         "resultdb_host",
    70  				IsIncludedByAncestor: true,
    71  			},
    72  			BuildJoinedTime:      time.Date(2020, time.December, 11, 1, 1, 1, uniqifier*1000, time.UTC),
    73  			HasInvocation:        true,
    74  			InvocationProject:    "invocation-project",
    75  			InvocationResult:     &controlpb.InvocationResult{},
    76  			InvocationJoinedTime: time.Date(2020, time.December, 12, 1, 1, 1, uniqifier*1000, time.UTC),
    77  			IsPresubmit:          true,
    78  			PresubmitProject:     "presubmit-project",
    79  			PresubmitResult: &controlpb.PresubmitResult{
    80  				PresubmitRunId: &pb.PresubmitRunId{
    81  					System: "luci-cv",
    82  					Id:     fmt.Sprintf("%s/123123-%v", "presubmit-project", uniqifier),
    83  				},
    84  				Status:       pb.PresubmitRunStatus_PRESUBMIT_RUN_STATUS_SUCCEEDED,
    85  				Mode:         pb.PresubmitRunMode_QUICK_DRY_RUN,
    86  				Owner:        "automation",
    87  				CreationTime: timestamppb.New(time.Date(2026, time.December, 1, 1, 2, 3, uniqifier*1000, time.UTC)),
    88  			},
    89  			PresubmitJoinedTime: time.Date(2020, time.December, 13, 1, 1, 1, uniqifier*1000, time.UTC),
    90  			LastUpdated:         time.Date(2020, time.December, 14, 1, 1, 1, uniqifier*1000, time.UTC),
    91  			TaskCount:           int64(uniqifier),
    92  		},
    93  	}
    94  }
    95  
    96  // WithBuildID specifies the build ID to use on the ingestion control record.
    97  func (b *EntryBuilder) WithBuildID(id string) *EntryBuilder {
    98  	b.record.BuildID = id
    99  	return b
   100  }
   101  
   102  // WithBuildProject specifies the build project to use on the ingestion control record.
   103  func (b *EntryBuilder) WithBuildProject(project string) *EntryBuilder {
   104  	b.record.BuildProject = project
   105  	return b
   106  }
   107  
   108  // WithBuildResult specifies the build result for the entry.
   109  func (b *EntryBuilder) WithBuildResult(value *controlpb.BuildResult) *EntryBuilder {
   110  	b.record.BuildResult = value
   111  	return b
   112  }
   113  
   114  // WithBuildJoinedTime specifies the time the build result was populated.
   115  func (b *EntryBuilder) WithBuildJoinedTime(value time.Time) *EntryBuilder {
   116  	b.record.BuildJoinedTime = value
   117  	return b
   118  }
   119  
   120  // WithHasInvocation specifies whether the build that is the subject of the ingestion
   121  // has a ResultDB invocation.
   122  func (b *EntryBuilder) WithHasInvocation(hasInvocation bool) *EntryBuilder {
   123  	b.record.HasInvocation = hasInvocation
   124  	return b
   125  }
   126  
   127  // WithInvocationProject specifies the invocation project to use on the ingestion control record.
   128  func (b *EntryBuilder) WithInvocationProject(project string) *EntryBuilder {
   129  	b.record.InvocationProject = project
   130  	return b
   131  }
   132  
   133  // WithInvocationResult specifies the invocation result for the entry.
   134  func (b *EntryBuilder) WithInvocationResult(value *controlpb.InvocationResult) *EntryBuilder {
   135  	b.record.InvocationResult = value
   136  	return b
   137  }
   138  
   139  // WithInvocationJoinedTime specifies the time the invocation result was populated.
   140  func (b *EntryBuilder) WithInvocationJoinedTime(value time.Time) *EntryBuilder {
   141  	b.record.InvocationJoinedTime = value
   142  	return b
   143  }
   144  
   145  // WithIsPresubmit specifies whether the ingestion relates to a presubmit run.
   146  func (b *EntryBuilder) WithIsPresubmit(isPresubmit bool) *EntryBuilder {
   147  	b.record.IsPresubmit = isPresubmit
   148  	return b
   149  }
   150  
   151  // WithPresubmitProject specifies the presubmit project to use on the ingestion control record.
   152  func (b *EntryBuilder) WithPresubmitProject(project string) *EntryBuilder {
   153  	b.record.PresubmitProject = project
   154  	return b
   155  }
   156  
   157  // WithPresubmitResult specifies the build result for the entry.
   158  func (b *EntryBuilder) WithPresubmitResult(value *controlpb.PresubmitResult) *EntryBuilder {
   159  	b.record.PresubmitResult = value
   160  	return b
   161  }
   162  
   163  // WithPresubmitJoinedTime specifies the time the presubmit result was populated.
   164  func (b *EntryBuilder) WithPresubmitJoinedTime(lastUpdated time.Time) *EntryBuilder {
   165  	b.record.PresubmitJoinedTime = lastUpdated
   166  	return b
   167  }
   168  
   169  func (b *EntryBuilder) WithTaskCount(taskCount int64) *EntryBuilder {
   170  	b.record.TaskCount = taskCount
   171  	return b
   172  }
   173  
   174  // Build constructs the entry.
   175  func (b *EntryBuilder) Build() *Entry {
   176  	return b.record
   177  }
   178  
   179  // SetEntriesForTesting replaces the set of stored entries to match the given set.
   180  func SetEntriesForTesting(ctx context.Context, es ...*Entry) (time.Time, error) {
   181  	testutil.MustApply(ctx,
   182  		spanner.Delete("Ingestions", spanner.AllKeys()))
   183  	// Insert some Ingestion records.
   184  	commitTime, err := span.ReadWriteTransaction(ctx, func(ctx context.Context) error {
   185  		for _, r := range es {
   186  			ms := spanutil.InsertMap("Ingestions", map[string]any{
   187  				"BuildId":              r.BuildID,
   188  				"BuildProject":         r.BuildProject,
   189  				"BuildResult":          r.BuildResult,
   190  				"BuildJoinedTime":      r.BuildJoinedTime,
   191  				"HasInvocation":        r.HasInvocation,
   192  				"InvocationProject":    r.InvocationProject,
   193  				"InvocationResult":     r.InvocationResult,
   194  				"InvocationJoinedTime": r.InvocationJoinedTime,
   195  				"IsPresubmit":          r.IsPresubmit,
   196  				"PresubmitProject":     r.PresubmitProject,
   197  				"PresubmitResult":      r.PresubmitResult,
   198  				"PresubmitJoinedTime":  r.PresubmitJoinedTime,
   199  				"LastUpdated":          r.LastUpdated,
   200  				"TaskCount":            r.TaskCount,
   201  			})
   202  			span.BufferWrite(ctx, ms)
   203  		}
   204  		return nil
   205  	})
   206  	return commitTime.In(time.UTC), err
   207  }