go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/buildbucket/cli/batch_test.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 cli 16 17 import ( 18 "context" 19 "testing" 20 21 "github.com/golang/mock/gomock" 22 "google.golang.org/grpc/codes" 23 "google.golang.org/grpc/status" 24 25 "go.chromium.org/luci/buildbucket" 26 "go.chromium.org/luci/common/proto" 27 28 pb "go.chromium.org/luci/buildbucket/proto" 29 30 . "github.com/smartystreets/goconvey/convey" 31 . "go.chromium.org/luci/common/testing/assertions" 32 ) 33 34 func TestSendBatchReq(t *testing.T) { 35 Convey("SendBatchReq", t, func() { 36 ctl := gomock.NewController(t) 37 defer ctl.Finish() 38 mockBBClient := pb.NewMockBuildsClient(ctl) 39 ctx := context.Background() 40 41 build := &pb.Build{ 42 Id: 1, 43 Builder: &pb.BuilderID{ 44 Project: "project", 45 Bucket: "bucket", 46 Builder: "builder1", 47 }, 48 Input: &pb.Build_Input{}, 49 } 50 51 Convey("success", func() { 52 req := &pb.BatchRequest{ 53 Requests: []*pb.BatchRequest_Request{ 54 {Request: &pb.BatchRequest_Request_ScheduleBuild{ 55 ScheduleBuild: &pb.ScheduleBuildRequest{}, 56 }}, 57 }, 58 } 59 expectedRes := &pb.BatchResponse{ 60 Responses: []*pb.BatchResponse_Response{ 61 {Response: &pb.BatchResponse_Response_ScheduleBuild{ 62 ScheduleBuild: build, 63 }}, 64 }, 65 } 66 mockBBClient.EXPECT().Batch(ctx, req).Return(expectedRes, nil) 67 res, err := sendBatchReq(ctx, req, mockBBClient) 68 So(err, ShouldBeNil) 69 So(res, ShouldResembleProto, expectedRes) 70 }) 71 72 Convey("sub-requests transient errors", func() { 73 req := &pb.BatchRequest{ 74 Requests: []*pb.BatchRequest_Request{ 75 {Request: &pb.BatchRequest_Request_ScheduleBuild{ 76 ScheduleBuild: &pb.ScheduleBuildRequest{}, 77 }}, 78 {Request: &pb.BatchRequest_Request_SearchBuilds{ 79 SearchBuilds: &pb.SearchBuildsRequest{}, 80 }}, 81 {Request: &pb.BatchRequest_Request_GetBuild{ 82 GetBuild: &pb.GetBuildRequest{Id: 1}, 83 }}, 84 }, 85 } 86 expectedRes := &pb.BatchResponse{ 87 Responses: []*pb.BatchResponse_Response{ 88 {Response: &pb.BatchResponse_Response_ScheduleBuild{ 89 ScheduleBuild: build, 90 }}, 91 {Response: &pb.BatchResponse_Response_SearchBuilds{ 92 SearchBuilds: &pb.SearchBuildsResponse{ 93 Builds: []*pb.Build{build}, 94 }, 95 }}, 96 {Response: &pb.BatchResponse_Response_Error{ 97 Error: status.New(codes.InvalidArgument, "bad request").Proto(), 98 }}, 99 }, 100 } 101 102 // first call 103 mockBBClient.EXPECT().Batch(ctx, req).Times(1).Return(&pb.BatchResponse{ 104 Responses: []*pb.BatchResponse_Response{ 105 {Response: &pb.BatchResponse_Response_ScheduleBuild{ 106 ScheduleBuild: build, 107 }}, 108 {Response: &pb.BatchResponse_Response_Error{ 109 Error: status.New(codes.Internal, "Internal server error").Proto(), 110 }}, 111 {Response: &pb.BatchResponse_Response_Error{ 112 Error: status.New(codes.Internal, "Internal server error").Proto(), 113 }}, 114 }, 115 }, nil) 116 // retry the 2nd and 3rd sub-requests 117 mockBBClient.EXPECT().Batch(ctx, proto.MatcherEqual( 118 &pb.BatchRequest{ 119 Requests: []*pb.BatchRequest_Request{ 120 {Request: &pb.BatchRequest_Request_SearchBuilds{ 121 SearchBuilds: &pb.SearchBuildsRequest{}, 122 }}, 123 {Request: &pb.BatchRequest_Request_GetBuild{ 124 GetBuild: &pb.GetBuildRequest{Id: 1}, 125 }}, 126 }, 127 })).Times(1).Return(&pb.BatchResponse{ 128 Responses: []*pb.BatchResponse_Response{ 129 {Response: &pb.BatchResponse_Response_Error{ 130 Error: status.New(codes.DeadlineExceeded, "timeout").Proto(), 131 }}, 132 {Response: &pb.BatchResponse_Response_Error{ 133 Error: status.New(codes.InvalidArgument, "bad request").Proto(), 134 }}, 135 }, 136 }, nil) 137 // retry the 2nd sub-request again 138 mockBBClient.EXPECT().Batch(ctx, proto.MatcherEqual( 139 &pb.BatchRequest{ 140 Requests: []*pb.BatchRequest_Request{ 141 {Request: &pb.BatchRequest_Request_SearchBuilds{ 142 SearchBuilds: &pb.SearchBuildsRequest{}, 143 }}, 144 }, 145 })).Times(1).Return(&pb.BatchResponse{ 146 Responses: []*pb.BatchResponse_Response{ 147 {Response: &pb.BatchResponse_Response_SearchBuilds{ 148 SearchBuilds: &pb.SearchBuildsResponse{ 149 Builds: []*pb.Build{build}, 150 }, 151 }}, 152 }, 153 }, nil) 154 res, err := sendBatchReq(ctx, req, mockBBClient) 155 So(err, ShouldBeNil) 156 So(res, ShouldResembleProto, expectedRes) 157 }) 158 }) 159 Convey("updateRequest", t, func() { 160 ctx := context.Background() 161 Convey("updateRequest if dummy token", func() { 162 req := &pb.BatchRequest{ 163 Requests: []*pb.BatchRequest_Request{ 164 {Request: &pb.BatchRequest_Request_ScheduleBuild{ 165 ScheduleBuild: &pb.ScheduleBuildRequest{ 166 CanOutliveParent: pb.Trinary_YES, 167 }, 168 }}, 169 }, 170 } 171 updateRequest(ctx, req, buildbucket.DummyBuildbucketToken) 172 So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_UNSET) 173 }) 174 Convey("updateRequest if empty token", func() { 175 req := &pb.BatchRequest{ 176 Requests: []*pb.BatchRequest_Request{ 177 {Request: &pb.BatchRequest_Request_ScheduleBuild{ 178 ScheduleBuild: &pb.ScheduleBuildRequest{ 179 CanOutliveParent: pb.Trinary_YES, 180 }, 181 }}, 182 }, 183 } 184 updateRequest(ctx, req, "") 185 So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_YES) 186 }) 187 Convey("updateRequest if real token", func() { 188 req := &pb.BatchRequest{ 189 Requests: []*pb.BatchRequest_Request{ 190 {Request: &pb.BatchRequest_Request_ScheduleBuild{ 191 ScheduleBuild: &pb.ScheduleBuildRequest{ 192 CanOutliveParent: pb.Trinary_YES, 193 }, 194 }}, 195 }, 196 } 197 updateRequest(ctx, req, "real token") 198 So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_YES) 199 }) 200 }) 201 }