go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/sink/testutil_test.go (about) 1 // Copyright 2020 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 sink 16 17 import ( 18 "context" 19 "io/ioutil" 20 "net/http" 21 "os" 22 "time" 23 24 "google.golang.org/grpc" 25 "google.golang.org/grpc/metadata" 26 "google.golang.org/protobuf/types/known/durationpb" 27 "google.golang.org/protobuf/types/known/timestamppb" 28 29 "go.chromium.org/luci/common/clock/testclock" 30 "go.chromium.org/luci/grpc/prpc" 31 32 "go.chromium.org/luci/resultdb/pbutil" 33 pb "go.chromium.org/luci/resultdb/proto/v1" 34 sinkpb "go.chromium.org/luci/resultdb/sink/proto/v1" 35 36 . "github.com/smartystreets/goconvey/convey" 37 ) 38 39 func reportTestResults(ctx context.Context, host, authToken string, in *sinkpb.ReportTestResultsRequest) (*sinkpb.ReportTestResultsResponse, error) { 40 sinkClient := sinkpb.NewSinkPRPCClient(&prpc.Client{ 41 Host: host, 42 Options: &prpc.Options{Insecure: true}, 43 }) 44 // install the auth token into the context, if present 45 if authToken != "" { 46 ctx = metadata.AppendToOutgoingContext(ctx, AuthTokenKey, authTokenValue(authToken)) 47 } 48 return sinkClient.ReportTestResults(ctx, in) 49 } 50 51 func testServerConfig(addr, tk string) ServerConfig { 52 return ServerConfig{ 53 Address: addr, 54 AuthToken: tk, 55 ArtifactStreamClient: &http.Client{}, 56 ArtifactStreamHost: "example.org", 57 Recorder: &mockRecorder{}, 58 Invocation: "invocations/u-foo-1587421194_893166206", 59 invocationID: "u-foo-1587421194_893166206", 60 UpdateToken: "UpdateToken-ABC", 61 MaxBatchableArtifactSize: 2 * 1024 * 1024, 62 } 63 } 64 65 func testArtifactWithFile(writer func(f *os.File)) *sinkpb.Artifact { 66 f, err := ioutil.TempFile("", "test-artifact") 67 So(err, ShouldBeNil) 68 defer f.Close() 69 writer(f) 70 71 return &sinkpb.Artifact{ 72 Body: &sinkpb.Artifact_FilePath{FilePath: f.Name()}, 73 ContentType: "text/plain", 74 } 75 } 76 77 func testArtifactWithContents(contents []byte) *sinkpb.Artifact { 78 return &sinkpb.Artifact{ 79 Body: &sinkpb.Artifact_Contents{Contents: contents}, 80 ContentType: "text/plain", 81 } 82 } 83 84 func testArtifactWithGcs(gcsURI string) *sinkpb.Artifact { 85 return &sinkpb.Artifact{ 86 Body: &sinkpb.Artifact_GcsUri{GcsUri: gcsURI}, 87 ContentType: "text/plain", 88 } 89 } 90 91 // validTestResult returns a valid sinkpb.TestResult sample message. 92 func validTestResult() (*sinkpb.TestResult, func()) { 93 now := testclock.TestRecentTimeUTC 94 st := timestamppb.New(now.Add(-2 * time.Minute)) 95 artf := testArtifactWithFile(func(f *os.File) { 96 _, err := f.WriteString("a sample artifact") 97 So(err, ShouldBeNil) 98 }) 99 cleanup := func() { os.Remove(artf.GetFilePath()) } 100 101 return &sinkpb.TestResult{ 102 TestId: "this is testID", 103 ResultId: "result_id1", 104 Expected: true, 105 Status: pb.TestStatus_PASS, 106 SummaryHtml: "HTML summary", 107 StartTime: st, 108 Duration: durationpb.New(time.Minute), 109 Tags: pbutil.StringPairs("k1", "v1"), 110 Variant: pbutil.Variant(), 111 Artifacts: map[string]*sinkpb.Artifact{ 112 "art1": artf, 113 }, 114 TestMetadata: &pb.TestMetadata{ 115 Name: "name", 116 Location: &pb.TestLocation{ 117 Repo: "https://chromium.googlesource.com/chromium/src", 118 FileName: "//artifact_dir/a_test.cc", 119 Line: 54, 120 }, 121 BugComponent: &pb.BugComponent{ 122 System: &pb.BugComponent_Monorail{ 123 Monorail: &pb.MonorailComponent{ 124 Project: "chromium", 125 Value: "Component>Value", 126 }, 127 }, 128 }, 129 }, 130 FailureReason: &pb.FailureReason{ 131 PrimaryErrorMessage: "This is a failure message.", 132 Errors: []*pb.FailureReason_Error{ 133 {Message: "This is a failure message."}, 134 {Message: "This is a failure message2."}, 135 }, 136 TruncatedErrorsCount: 0, 137 }, 138 }, cleanup 139 } 140 141 type mockRecorder struct { 142 pb.RecorderClient 143 batchCreateTestResults func(ctx context.Context, in *pb.BatchCreateTestResultsRequest) (*pb.BatchCreateTestResultsResponse, error) 144 batchCreateArtifacts func(ctx context.Context, in *pb.BatchCreateArtifactsRequest) (*pb.BatchCreateArtifactsResponse, error) 145 batchCreateTestExonerations func(ctx context.Context, in *pb.BatchCreateTestExonerationsRequest) (*pb.BatchCreateTestExonerationsResponse, error) 146 } 147 148 func (m *mockRecorder) BatchCreateTestResults(ctx context.Context, in *pb.BatchCreateTestResultsRequest, opts ...grpc.CallOption) (*pb.BatchCreateTestResultsResponse, error) { 149 if m.batchCreateTestResults != nil { 150 return m.batchCreateTestResults(ctx, in) 151 } 152 return nil, nil 153 } 154 155 func (m *mockRecorder) BatchCreateArtifacts(ctx context.Context, in *pb.BatchCreateArtifactsRequest, opts ...grpc.CallOption) (*pb.BatchCreateArtifactsResponse, error) { 156 if m.batchCreateArtifacts != nil { 157 return m.batchCreateArtifacts(ctx, in) 158 } 159 return nil, nil 160 } 161 162 func (m *mockRecorder) BatchCreateTestExonerations(ctx context.Context, in *pb.BatchCreateTestExonerationsRequest, opts ...grpc.CallOption) (*pb.BatchCreateTestExonerationsResponse, error) { 163 if m.batchCreateTestExonerations != nil { 164 return m.batchCreateTestExonerations(ctx, in) 165 } 166 return nil, nil 167 }