| package internal |
| |
| import ( |
| "testing" |
| |
| "github.com/stretchr/testify/mock" |
| buildbucketpb "go.chromium.org/luci/buildbucket/proto" |
| |
| "go.skia.org/infra/go/swarming" |
| "go.skia.org/infra/pinpoint/go/backends" |
| "go.skia.org/infra/pinpoint/go/common" |
| "go.skia.org/infra/pinpoint/go/run_benchmark" |
| "go.skia.org/infra/pinpoint/go/workflows" |
| |
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/require" |
| "go.temporal.io/sdk/testsuite" |
| "go.temporal.io/sdk/workflow" |
| ) |
| |
| // generateTestRuns generates a test runs data |
| // |
| // It returns the expected runs, and a channel that was buffered to send to mocked workflow. |
| func generateTestRuns(chart string, c int, chartExpectedValues *workflows.TestResults) (trs []*workflows.TestRun, rc chan *workflows.TestRun) { |
| rc = make(chan *workflows.TestRun, c) |
| trs = make([]*workflows.TestRun, c) |
| trs[0] = &workflows.TestRun{ |
| Status: run_benchmark.State(backends.RunBenchmarkFailure), |
| } |
| rc <- &workflows.TestRun{ |
| Status: run_benchmark.State(backends.RunBenchmarkFailure), |
| } |
| for i := 1; i < c; i++ { |
| trs[i] = &workflows.TestRun{ |
| Status: run_benchmark.State(swarming.TASK_STATE_COMPLETED), |
| Values: map[string][]float64{ |
| chart: chartExpectedValues.Values[chart], |
| }, |
| } |
| rc <- &workflows.TestRun{ |
| Status: run_benchmark.State(swarming.TASK_STATE_COMPLETED), |
| } |
| } |
| |
| return trs, rc |
| } |
| |
| func TestSingleCommitRunner_GivenValidInput_ShouldReturnValues(t *testing.T) { |
| testSuite := &testsuite.WorkflowTestSuite{} |
| env := testSuite.NewTestWorkflowEnvironment() |
| |
| b := &workflows.Build{ |
| ID: int64(1234), |
| Status: buildbucketpb.Status_SUCCESS, |
| } |
| const iterations, chart = 5, "fake-chart" |
| fakeChartValues := &workflows.TestResults{ |
| Values: map[string][]float64{ |
| chart: {1, 2, 3, 4}, |
| }, |
| } |
| trs, rc := generateTestRuns(chart, iterations, fakeChartValues) |
| |
| env.RegisterWorkflowWithOptions(BuildWorkflow, workflow.RegisterOptions{Name: workflows.BuildChrome}) |
| env.RegisterWorkflowWithOptions(RunBenchmarkWorkflow, workflow.RegisterOptions{Name: workflows.RunBenchmark}) |
| |
| env.OnWorkflow(workflows.BuildChrome, mock.Anything, mock.Anything).Return(b, nil).Once() |
| env.OnWorkflow(workflows.RunBenchmark, mock.Anything, mock.Anything).Return(func(ctx workflow.Context, b *RunBenchmarkParams) (*workflows.TestRun, error) { |
| return <-rc, nil |
| }).Times(iterations) |
| // TestRun with RunBenchmarkFailure status will not collect data |
| env.OnActivity(CollectValuesActivity, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fakeChartValues, nil).Times(iterations - 1) |
| |
| env.ExecuteWorkflow(SingleCommitRunner, &SingleCommitRunnerParams{ |
| BotConfig: "linux-perf", |
| Iterations: int32(iterations), |
| Chart: chart, |
| CombinedCommit: &common.CombinedCommit{}, |
| }) |
| require.True(t, env.IsWorkflowCompleted()) |
| require.NoError(t, env.GetWorkflowError()) |
| |
| var cr *CommitRun |
| require.NoError(t, env.GetWorkflowResult(&cr)) |
| require.NotNil(t, cr) |
| require.Equal(t, *b, *cr.Build) |
| require.EqualValues(t, trs, cr.Runs) |
| env.AssertExpectations(t) |
| } |
| |
| func TestSingleCommitRunner_WithExtraArgs_ShouldPassToRunBenchmark(t *testing.T) { |
| testSuite := &testsuite.WorkflowTestSuite{} |
| env := testSuite.NewTestWorkflowEnvironment() |
| |
| b := &workflows.Build{ |
| ID: int64(1234), |
| Status: buildbucketpb.Status_SUCCESS, |
| } |
| const iterations, chart = 2, "fake-chart" |
| fakeChartValues := &workflows.TestResults{ |
| Values: map[string][]float64{ |
| chart: {1, 2}, |
| }, |
| } |
| _, rc := generateTestRuns(chart, iterations, fakeChartValues) |
| |
| env.RegisterWorkflowWithOptions(BuildWorkflow, workflow.RegisterOptions{Name: workflows.BuildChrome}) |
| env.RegisterWorkflowWithOptions(RunBenchmarkWorkflow, workflow.RegisterOptions{Name: workflows.RunBenchmark}) |
| |
| env.OnWorkflow(workflows.BuildChrome, mock.Anything, mock.Anything).Return(b, nil).Once() |
| |
| // Assert that the mock RunBenchmark child workflow is called with the expected ExtraArgs |
| env.OnWorkflow(workflows.RunBenchmark, mock.Anything, mock.MatchedBy(func(params *RunBenchmarkParams) bool { |
| return len(params.ExtraArgs) == 2 && params.ExtraArgs[0] == "--custom-arg" && params.ExtraArgs[1] == "value" |
| })).Return(func(ctx workflow.Context, b *RunBenchmarkParams) (*workflows.TestRun, error) { |
| return <-rc, nil |
| }).Times(iterations) |
| |
| env.OnActivity(CollectValuesActivity, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fakeChartValues, nil).Times(iterations - 1) |
| |
| env.ExecuteWorkflow(SingleCommitRunner, &SingleCommitRunnerParams{ |
| BotConfig: "linux-perf", |
| Iterations: int32(iterations), |
| Chart: chart, |
| CombinedCommit: &common.CombinedCommit{}, |
| ExtraArgs: []string{"--custom-arg", "value"}, |
| }) |
| require.True(t, env.IsWorkflowCompleted()) |
| require.NoError(t, env.GetWorkflowError()) |
| env.AssertExpectations(t) |
| } |
| |
| func TestAllValues_GivenNilValues_ReturnsNonNilValues(t *testing.T) { |
| const chart = "chart" |
| cr := &CommitRun{ |
| Runs: []*workflows.TestRun{ |
| { |
| Values: map[string][]float64{ |
| chart: {1.0, 2.0, 3.0}, |
| }, |
| }, |
| {}, |
| { |
| Values: map[string][]float64{ |
| chart: {4.0, 5.0, 6.0}, |
| }, |
| }, |
| }, |
| } |
| actual := cr.AllValues(chart) |
| assert.Equal(t, []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}, actual) |
| } |
| |
| func TestGetBotDimensions_GivenValidInput_ShouldReturnBotDimensions(t *testing.T) { |
| freeBots := []string{ |
| "build-h1-device0", |
| "build-h1-device1", |
| "build-h1-device2", |
| "build-h1-device3", |
| "build-h1-device4", |
| } |
| |
| type args struct { |
| finishedIteration int32 |
| iteration int32 |
| } |
| |
| wantDevice1 := map[string]string{ |
| "key": "id", |
| "value": "build-h1-device1", |
| } |
| |
| wantDevice2 := map[string]string{ |
| "key": "id", |
| "value": "build-h1-device2", |
| } |
| |
| wantDevice4 := map[string]string{ |
| "key": "id", |
| "value": "build-h1-device4", |
| } |
| |
| tests := []struct { |
| name string |
| args args |
| want map[string]string |
| }{ |
| { |
| name: "The first round of commit run with no finished iteration", |
| args: args{0, 1}, |
| want: wantDevice1, |
| }, |
| { |
| name: "Commit run total iteration number smaller than bot number", |
| args: args{1, 3}, |
| want: wantDevice4, |
| }, |
| { |
| name: "Commit run total iteration number larger than bot number", |
| args: args{4, 8}, |
| want: wantDevice2, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| got := getBotDimension(tt.args.finishedIteration, tt.args.iteration, freeBots) |
| assert.Equal(t, tt.want, got, "Test case %s failed!", tt.name) |
| }) |
| } |
| } |
| |
| func TestGetBotDimensions_GivenInValidInput_ShouldNotReturnBotDimensions(t *testing.T) { |
| gotBotDimensionsWithNilBotList := getBotDimension(1, 2, nil) |
| assert.Nil(t, gotBotDimensionsWithNilBotList) |
| |
| gotBotDimensionsWithEmptyBotList := getBotDimension(1, 2, make([]string, 0)) |
| assert.Nil(t, gotBotDimensionsWithEmptyBotList) |
| } |
| |
| func TestGetSwarmingStatus_GivenNilRuns_ReturnsEmpty(t *testing.T) { |
| test := func(name string, cr CommitRun) { |
| t.Run(name, func(t *testing.T) { |
| status := cr.GetSwarmingStatus() |
| assert.Empty(t, status) |
| }) |
| } |
| var cr CommitRun |
| test("CommitRun is nil", cr) |
| |
| cr = CommitRun{ |
| Runs: nil, |
| } |
| test("CommitRun.Runs is nil", cr) |
| |
| cr = CommitRun{ |
| Runs: []*workflows.TestRun{}, |
| } |
| test("CommitRun.Runs is empty", cr) |
| } |