blob: 5e97f51be103a3331a938aeaf200495532c7bba6 [file] [log] [blame]
package build_chrome
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
buildbucketpb "go.chromium.org/luci/buildbucket/proto"
swarmingV1 "go.chromium.org/luci/common/api/swarming/swarming/v1"
"google.golang.org/protobuf/types/known/timestamppb"
"go.skia.org/infra/bisection/go/backends"
"go.skia.org/infra/bisection/go/backends/mocks"
"go.skia.org/infra/go/testutils"
)
func TestSearchBuild(t *testing.T) {
for i, test := range []struct {
name string
builder string
mockResp interface{}
expected int64
expectedErrorDeps bool
expectedErrorCI bool
}{
{
name: "buildbucket search error",
builder: "builder",
expected: 0,
expectedErrorDeps: true,
expectedErrorCI: false,
},
{
name: "build found",
builder: "builder",
mockResp: &buildbucketpb.Build{
Id: 1,
Status: buildbucketpb.Status_SUCCESS,
EndTime: timestamppb.Now(),
Input: &buildbucketpb.Build_Input{
GerritChanges: []*buildbucketpb.GerritChange{},
},
},
expected: 1,
expectedErrorDeps: false,
expectedErrorCI: false,
},
{
name: "build found through CI counterpart",
builder: "builder",
mockResp: &buildbucketpb.Build{
Id: 1,
Status: buildbucketpb.Status_FAILURE,
EndTime: timestamppb.Now(),
Input: &buildbucketpb.Build_Input{
GerritChanges: []*buildbucketpb.GerritChange{},
},
},
expected: 1,
expectedErrorDeps: true,
expectedErrorCI: false,
},
{
name: "build not found",
builder: "builder",
expected: 0,
expectedErrorDeps: false,
expectedErrorCI: false,
},
} {
t.Run(fmt.Sprintf("[%d] %s", i, test.name), func(t *testing.T) {
ctx := context.Background()
mb := &mocks.Buildbucket{}
bc := &BuildChrome{
Builder: test.builder,
Client: mb,
Commit: "commit",
}
if test.expectedErrorDeps {
mb.On("GetBuildWithPatches", testutils.AnyContext, bc.Builder, backends.DefaultBucket, bc.Commit, bc.Patch).Return(nil, fmt.Errorf("random error"))
} else {
mb.On("GetBuildWithPatches", testutils.AnyContext, bc.Builder, backends.DefaultBucket, bc.Commit, bc.Patch).Return(test.mockResp, nil)
}
if test.expectedErrorCI {
mb.On("GetBuildFromWaterfall", testutils.AnyContext, bc.Builder, bc.Commit).Return(nil, fmt.Errorf("random error"))
} else {
mb.On("GetBuildFromWaterfall", testutils.AnyContext, bc.Builder, bc.Commit).Return(test.mockResp, nil)
}
id, err := bc.searchBuild(ctx, test.builder)
if (test.expectedErrorDeps && !test.expectedErrorCI) || (test.expectedErrorDeps && test.expectedErrorCI) {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, test.expected, id)
}
})
}
}
func TestCheckBuildStatus(t *testing.T) {
for i, test := range []struct {
name string
mockResp buildbucketpb.Status
expected buildbucketpb.Status
expectedError bool
}{
{
name: "build success",
mockResp: buildbucketpb.Status_SUCCESS,
expected: buildbucketpb.Status_SUCCESS,
expectedError: false,
},
{
name: "build failed",
mockResp: buildbucketpb.Status_FAILURE,
expected: buildbucketpb.Status_FAILURE,
expectedError: false,
},
{
name: "GetBuildStatus error",
expected: buildbucketpb.Status_STATUS_UNSPECIFIED,
expectedError: true,
},
} {
t.Run(fmt.Sprintf("[%d] %s", i, test.name), func(t *testing.T) {
ctx := context.Background()
buildID := int64(0)
mb := &mocks.Buildbucket{}
bc := &BuildChrome{
Client: mb,
}
if test.expectedError {
mb.On("GetBuildStatus", testutils.AnyContext, buildID).Return(buildbucketpb.Status_STATUS_UNSPECIFIED, fmt.Errorf("some error"))
} else {
mb.On("GetBuildStatus", testutils.AnyContext, buildID).Return(test.mockResp, nil)
}
status, err := bc.CheckBuildStatus(ctx, buildID)
if test.expectedError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, test.expected, status)
})
}
}
func TestBuildNonExistentDevice(t *testing.T) {
ctx := context.Background()
mb := &mocks.Buildbucket{}
bc := BuildChrome{
Client: mb,
Device: "non-existent device",
Target: "target",
Commit: "commit",
}
jID := "1"
id, err := bc.Run(ctx, jID)
assert.Error(t, err)
assert.Zero(t, id)
}
func TestBuildFound(t *testing.T) {
mockResp := &buildbucketpb.Build{
Id: 1,
Status: buildbucketpb.Status_SUCCESS,
EndTime: timestamppb.Now(),
Input: &buildbucketpb.Build_Input{
GerritChanges: []*buildbucketpb.GerritChange{},
},
}
expected := int64(1)
ctx := context.Background()
mb := &mocks.Buildbucket{}
bc := BuildChrome{
Client: mb,
Device: "linux-perf",
Target: "target",
Commit: "commit",
}
mb.On("GetBuildWithPatches", testutils.AnyContext, "Linux Builder Perf", backends.DefaultBucket, bc.Commit, bc.Patch).Return(mockResp, nil)
jID := "1"
id, err := bc.Run(ctx, jID)
assert.NoError(t, err)
assert.Equal(t, expected, id)
}
func TestNewBuild(t *testing.T) {
for i, test := range []struct {
name string
mockResp *buildbucketpb.Build
expected int64
expectedError bool
}{
{
name: "build success",
mockResp: &buildbucketpb.Build{
Id: 1,
},
expected: 1,
expectedError: false,
},
{
name: "build failed",
expected: 0,
expectedError: true,
},
} {
t.Run(fmt.Sprintf("[%d] %s", i, test.name), func(t *testing.T) {
ctx := context.Background()
mb := &mocks.Buildbucket{}
bc := BuildChrome{
Client: mb,
Device: "linux-perf",
Target: "target",
Commit: "commit",
}
builder := "Linux Builder Perf"
mb.On("GetBuildWithPatches", testutils.AnyContext, builder, backends.DefaultBucket, bc.Commit, bc.Patch).Return(nil, nil)
mb.On("GetBuildFromWaterfall", testutils.AnyContext, builder, bc.Commit).Return(nil, nil)
if test.expectedError {
mb.On("StartChromeBuild", testutils.AnyContext, mock.Anything, mock.Anything, builder, bc.Commit, bc.Patch).Return(nil, fmt.Errorf("some error"))
} else {
mb.On("StartChromeBuild", testutils.AnyContext, mock.Anything, mock.Anything, builder, bc.Commit, bc.Patch).Return(test.mockResp, nil)
}
jID := "1"
id, err := bc.Run(ctx, jID)
if test.expectedError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, test.expected, id)
})
}
}
func TestRetrieveCAS(t *testing.T) {
for i, test := range []struct {
name string
mockResp *swarmingV1.SwarmingRpcsCASReference
expected *swarmingV1.SwarmingRpcsDigest
expectedError bool
}{
{
name: "build failed or ongoing",
expected: nil,
expectedError: true,
},
{
name: "retrieve cas success",
mockResp: &swarmingV1.SwarmingRpcsCASReference{
CasInstance: backends.DefaultCASInstance,
Digest: &swarmingV1.SwarmingRpcsDigest{
Hash: "hash",
SizeBytes: 123,
},
},
expected: &swarmingV1.SwarmingRpcsDigest{
Hash: "hash",
SizeBytes: 123,
},
expectedError: false,
},
} {
t.Run(fmt.Sprintf("[%d] %s", i, test.name), func(t *testing.T) {
ctx := context.Background()
mb := &mocks.Buildbucket{}
bc := BuildChrome{
Client: mb,
Target: "target",
}
buildID := int64(0)
if test.expectedError {
mb.On("GetCASReference", testutils.AnyContext, buildID, bc.Target).Return(nil, fmt.Errorf("some error"))
} else {
mb.On("GetCASReference", testutils.AnyContext, buildID, bc.Target).Return(test.mockResp, nil)
}
cas, err := bc.RetrieveCAS(ctx, buildID)
if test.expectedError {
assert.Error(t, err)
assert.Nil(t, cas)
} else {
assert.NoError(t, err)
assert.Equal(t, test.expected.Hash, cas.Digest.Hash)
assert.Equal(t, test.expected.SizeBytes, cas.Digest.SizeBytes)
}
})
}
}