go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/services/recorder/batch_create_test_exonerations.go (about) 1 // Copyright 2019 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 recorder 16 17 import ( 18 "context" 19 20 "cloud.google.com/go/spanner" 21 22 "go.chromium.org/luci/common/errors" 23 "go.chromium.org/luci/grpc/appstatus" 24 "go.chromium.org/luci/resultdb/internal/invocations" 25 "go.chromium.org/luci/resultdb/pbutil" 26 pb "go.chromium.org/luci/resultdb/proto/v1" 27 "go.chromium.org/luci/server/span" 28 ) 29 30 func validateBatchCreateTestExonerationsRequest(req *pb.BatchCreateTestExonerationsRequest) error { 31 if err := pbutil.ValidateInvocationName(req.Invocation); err != nil { 32 return errors.Annotate(err, "invocation").Err() 33 } 34 35 if err := pbutil.ValidateRequestID(req.RequestId); err != nil { 36 return errors.Annotate(err, "request_id").Err() 37 } 38 39 if err := pbutil.ValidateBatchRequestCount(len(req.Requests)); err != nil { 40 return err 41 } 42 43 for i, sub := range req.Requests { 44 if err := validateCreateTestExonerationRequest(sub, false); err != nil { 45 return errors.Annotate(err, "requests[%d]", i).Err() 46 } 47 if sub.Invocation != "" && sub.Invocation != req.Invocation { 48 return errors.Reason("requests[%d]: invocation: inconsistent with top-level invocation", i).Err() 49 } 50 if sub.RequestId != "" && sub.RequestId != req.RequestId { 51 return errors.Reason("requests[%d]: request_id: inconsistent with top-level request_id", i).Err() 52 } 53 } 54 return nil 55 } 56 57 // BatchCreateTestExonerations implements pb.RecorderServer. 58 func (s *recorderServer) BatchCreateTestExonerations(ctx context.Context, in *pb.BatchCreateTestExonerationsRequest) (rsp *pb.BatchCreateTestExonerationsResponse, err error) { 59 if err := validateBatchCreateTestExonerationsRequest(in); err != nil { 60 return nil, appstatus.BadRequest(err) 61 } 62 63 invID := invocations.MustParseName(in.Invocation) 64 65 ret := &pb.BatchCreateTestExonerationsResponse{ 66 TestExonerations: make([]*pb.TestExoneration, len(in.Requests)), 67 } 68 ms := make([]*spanner.Mutation, len(in.Requests)) 69 for i, sub := range in.Requests { 70 ret.TestExonerations[i], ms[i] = insertTestExoneration(ctx, invID, in.RequestId, i, sub.TestExoneration) 71 } 72 err = mutateInvocation(ctx, invID, func(ctx context.Context) error { 73 span.BufferWrite(ctx, ms...) 74 return nil 75 }) 76 if err != nil { 77 return nil, err 78 } 79 return ret, nil 80 }