blob: baf78e0c451966625df3aae79c2ec1b73d5ae3ae [file] [log] [blame]
// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"context"
"testing"
"github.com/golang/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"go.chromium.org/luci/buildbucket"
"go.chromium.org/luci/common/proto"
pb "go.chromium.org/luci/buildbucket/proto"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestSendBatchReq(t *testing.T) {
Convey("SendBatchReq", t, func() {
ctl := gomock.NewController(t)
defer ctl.Finish()
mockBBClient := pb.NewMockBuildsClient(ctl)
ctx := context.Background()
build := &pb.Build{
Id: 1,
Builder: &pb.BuilderID{
Project: "project",
Bucket: "bucket",
Builder: "builder1",
},
Input: &pb.Build_Input{},
}
Convey("success", func() {
req := &pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_ScheduleBuild{
ScheduleBuild: &pb.ScheduleBuildRequest{},
}},
},
}
expectedRes := &pb.BatchResponse{
Responses: []*pb.BatchResponse_Response{
{Response: &pb.BatchResponse_Response_ScheduleBuild{
ScheduleBuild: build,
}},
},
}
mockBBClient.EXPECT().Batch(ctx, req).Return(expectedRes, nil)
res, err := sendBatchReq(ctx, req, mockBBClient)
So(err, ShouldBeNil)
So(res, ShouldResembleProto, expectedRes)
})
Convey("sub-requests transient errors", func() {
req := &pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_ScheduleBuild{
ScheduleBuild: &pb.ScheduleBuildRequest{},
}},
{Request: &pb.BatchRequest_Request_SearchBuilds{
SearchBuilds: &pb.SearchBuildsRequest{},
}},
{Request: &pb.BatchRequest_Request_GetBuild{
GetBuild: &pb.GetBuildRequest{Id: 1},
}},
},
}
expectedRes := &pb.BatchResponse{
Responses: []*pb.BatchResponse_Response{
{Response: &pb.BatchResponse_Response_ScheduleBuild{
ScheduleBuild: build,
}},
{Response: &pb.BatchResponse_Response_SearchBuilds{
SearchBuilds: &pb.SearchBuildsResponse{
Builds: []*pb.Build{build},
},
}},
{Response: &pb.BatchResponse_Response_Error{
Error: status.New(codes.InvalidArgument, "bad request").Proto(),
}},
},
}
// first call
mockBBClient.EXPECT().Batch(ctx, req).Times(1).Return(&pb.BatchResponse{
Responses: []*pb.BatchResponse_Response{
{Response: &pb.BatchResponse_Response_ScheduleBuild{
ScheduleBuild: build,
}},
{Response: &pb.BatchResponse_Response_Error{
Error: status.New(codes.Internal, "Internal server error").Proto(),
}},
{Response: &pb.BatchResponse_Response_Error{
Error: status.New(codes.Internal, "Internal server error").Proto(),
}},
},
}, nil)
// retry the 2nd and 3rd sub-requests
mockBBClient.EXPECT().Batch(ctx, proto.MatcherEqual(
&pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_SearchBuilds{
SearchBuilds: &pb.SearchBuildsRequest{},
}},
{Request: &pb.BatchRequest_Request_GetBuild{
GetBuild: &pb.GetBuildRequest{Id: 1},
}},
},
})).Times(1).Return(&pb.BatchResponse{
Responses: []*pb.BatchResponse_Response{
{Response: &pb.BatchResponse_Response_Error{
Error: status.New(codes.DeadlineExceeded, "timeout").Proto(),
}},
{Response: &pb.BatchResponse_Response_Error{
Error: status.New(codes.InvalidArgument, "bad request").Proto(),
}},
},
}, nil)
// retry the 2nd sub-request again
mockBBClient.EXPECT().Batch(ctx, proto.MatcherEqual(
&pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_SearchBuilds{
SearchBuilds: &pb.SearchBuildsRequest{},
}},
},
})).Times(1).Return(&pb.BatchResponse{
Responses: []*pb.BatchResponse_Response{
{Response: &pb.BatchResponse_Response_SearchBuilds{
SearchBuilds: &pb.SearchBuildsResponse{
Builds: []*pb.Build{build},
},
}},
},
}, nil)
res, err := sendBatchReq(ctx, req, mockBBClient)
So(err, ShouldBeNil)
So(res, ShouldResembleProto, expectedRes)
})
})
Convey("updateRequest", t, func() {
ctx := context.Background()
Convey("updateRequest if dummy token", func() {
req := &pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_ScheduleBuild{
ScheduleBuild: &pb.ScheduleBuildRequest{
CanOutliveParent: pb.Trinary_YES,
},
}},
},
}
updateRequest(ctx, req, buildbucket.DummyBuildbucketToken)
So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_UNSET)
})
Convey("updateRequest if empty token", func() {
req := &pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_ScheduleBuild{
ScheduleBuild: &pb.ScheduleBuildRequest{
CanOutliveParent: pb.Trinary_YES,
},
}},
},
}
updateRequest(ctx, req, "")
So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_YES)
})
Convey("updateRequest if real token", func() {
req := &pb.BatchRequest{
Requests: []*pb.BatchRequest_Request{
{Request: &pb.BatchRequest_Request_ScheduleBuild{
ScheduleBuild: &pb.ScheduleBuildRequest{
CanOutliveParent: pb.Trinary_YES,
},
}},
},
}
updateRequest(ctx, req, "real token")
So(req.Requests[0].GetScheduleBuild().CanOutliveParent, ShouldEqual, pb.Trinary_YES)
})
})
}