blob: eb8894cb1d14ff723c1a7dca329a7fceaa9b9376 [file]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package backfill
import (
"testing"
"github.com/kylelemons/godebug/pretty"
"go.chromium.org/chromiumos/infra/proto/go/test_platform"
"go.chromium.org/chromiumos/infra/proto/go/test_platform/steps"
)
func TestPlanComputationForFailedRun(t *testing.T) {
cases := []struct {
Tag string
Enumeration *steps.EnumerationResponse
Execution *steps.ExecuteResponse
Want *test_platform.Request
}{
{
Tag: "no enumeration or execution",
Want: nil,
},
{
Tag: "one enumeration with zero value for task state",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_UNSPECIFIED,
test_platform.TaskState_VERDICT_UNSPECIFIED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with successful execution",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_COMPLETED,
test_platform.TaskState_VERDICT_PASSED,
),
Want: nil,
},
{
Tag: "one enumeration with successful execution",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_COMPLETED,
test_platform.TaskState_VERDICT_PASSED_ON_RETRY,
),
Want: nil,
},
{
Tag: "one enumeration without verdict",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_COMPLETED,
test_platform.TaskState_VERDICT_NO_VERDICT,
),
// No verdict implies there was no test case that could be run on
// the chosen DUT. The test did correctly get scheduled from test
// platform perspective and succeeded without any verdict.
Want: nil,
},
{
Tag: "one enumeration with failed execution",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_COMPLETED,
test_platform.TaskState_VERDICT_FAILED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with lifecycle pending",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_PENDING,
test_platform.TaskState_VERDICT_PASSED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with aborted task",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_ABORTED,
test_platform.TaskState_VERDICT_UNSPECIFIED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with rejected task",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithSingleAttempt(
test_platform.TaskState_LIFE_CYCLE_REJECTED,
test_platform.TaskState_VERDICT_UNSPECIFIED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with zero attempts",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithMultipleCompletedAttempts(),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with multiple failing attempts",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithMultipleCompletedAttempts(
test_platform.TaskState_VERDICT_FAILED,
test_platform.TaskState_VERDICT_FAILED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("some_test")),
},
{
Tag: "one enumeration with success on eventual attempt",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithMultipleCompletedAttempts(
test_platform.TaskState_VERDICT_FAILED,
test_platform.TaskState_VERDICT_PASSED,
),
Want: nil,
},
{
Tag: "two enumerations, one successful one failing",
Enumeration: enumerationsWithDisplayNames("failed_test", "passed_test"),
Execution: executeResponseWithMultipleSingleAttemptEnumerations(
test_platform.TaskState_VERDICT_FAILED,
test_platform.TaskState_VERDICT_PASSED,
),
Want: requestWithEnumeration(cannedParams(), enumerationsWithDisplayNames("failed_test")),
},
}
for _, c := range cases {
t.Run(c.Tag, func(t *testing.T) {
br, err := Compute(&steps.ComputeBackfillRequest{
Request: &test_platform.Request{Params: cannedParams()},
Enumeration: c.Enumeration,
Execution: c.Execution,
})
if err != nil {
t.Fatalf("Error in Compute(): %s", err)
}
if diff := pretty.Compare(c.Want, br.GetRequest()); diff != "" {
t.Errorf("Incorrect backfill request, -want +got: %s", diff)
}
})
}
}
func cannedParams() *test_platform.Request_Params {
return &test_platform.Request_Params{
HardwareAttributes: &test_platform.Request_Params_HardwareAttributes{
Model: "some-model",
},
}
}
func enumerationsWithDisplayNames(names ...string) *steps.EnumerationResponse {
resp := &steps.EnumerationResponse{
AutotestInvocations: make([]*steps.EnumerationResponse_AutotestInvocation, len(names)),
}
for i := range names {
resp.AutotestInvocations[i] = &steps.EnumerationResponse_AutotestInvocation{
DisplayName: names[i],
}
}
return resp
}
func executeResponseWithSingleAttempt(ls test_platform.TaskState_LifeCycle, v test_platform.TaskState_Verdict) *steps.ExecuteResponse {
return &steps.ExecuteResponse{
ConsolidatedResults: []*steps.ExecuteResponse_ConsolidatedResult{
{
Attempts: []*steps.ExecuteResponse_TaskResult{
{
State: &test_platform.TaskState{
LifeCycle: ls,
Verdict: v,
},
},
},
},
},
}
}
func executeResponseWithMultipleCompletedAttempts(vs ...test_platform.TaskState_Verdict) *steps.ExecuteResponse {
var as []*steps.ExecuteResponse_TaskResult
for _, v := range vs {
as = append(as, &steps.ExecuteResponse_TaskResult{
State: &test_platform.TaskState{
LifeCycle: test_platform.TaskState_LIFE_CYCLE_COMPLETED,
Verdict: v,
},
})
}
return &steps.ExecuteResponse{
ConsolidatedResults: []*steps.ExecuteResponse_ConsolidatedResult{
{
Attempts: as,
},
},
}
}
func executeResponseWithMultipleSingleAttemptEnumerations(vs ...test_platform.TaskState_Verdict) *steps.ExecuteResponse {
var cs []*steps.ExecuteResponse_ConsolidatedResult
for _, v := range vs {
cs = append(cs, &steps.ExecuteResponse_ConsolidatedResult{
Attempts: []*steps.ExecuteResponse_TaskResult{
{
State: &test_platform.TaskState{
LifeCycle: test_platform.TaskState_LIFE_CYCLE_COMPLETED,
Verdict: v,
},
},
},
})
}
return &steps.ExecuteResponse{
ConsolidatedResults: cs,
}
}
func requestWithEnumeration(p *test_platform.Request_Params, e *steps.EnumerationResponse) *test_platform.Request {
return &test_platform.Request{
Params: p,
TestPlan: testPlan(e),
}
}
func testPlan(e *steps.EnumerationResponse) *test_platform.Request_TestPlan {
ret := &test_platform.Request_TestPlan{
Enumeration: &test_platform.Request_Enumeration{
AutotestInvocations: make([]*test_platform.Request_Enumeration_AutotestInvocation, len(e.AutotestInvocations)),
},
}
for i := range e.AutotestInvocations {
ret.Enumeration.AutotestInvocations[i] = &test_platform.Request_Enumeration_AutotestInvocation{
DisplayName: e.AutotestInvocations[i].DisplayName,
}
}
return ret
}
func TestMismatchedEnumerationAndExecutionReturnsError(t *testing.T) {
cases := []struct {
Tag string
Enumeration *steps.EnumerationResponse
Execution *steps.ExecuteResponse
}{
{
Tag: "fewer enumerations than executions",
Enumeration: enumerationsWithDisplayNames("some_test"),
Execution: executeResponseWithMultipleSingleAttemptEnumerations(
test_platform.TaskState_VERDICT_FAILED,
test_platform.TaskState_VERDICT_PASSED,
),
},
{
Tag: "fewer executions than enumerations",
Enumeration: enumerationsWithDisplayNames("some_test", "some_other_test"),
Execution: executeResponseWithMultipleSingleAttemptEnumerations(),
},
}
for _, c := range cases {
t.Run(c.Tag, func(t *testing.T) {
_, err := Compute(&steps.ComputeBackfillRequest{
Request: &test_platform.Request{Params: cannedParams()},
Enumeration: c.Enumeration,
Execution: c.Execution,
})
if err == nil {
t.Errorf("No error in Compute()")
}
})
}
}