blob: 025c04aaf690f9523a098ff11a1f533650b3f9cc [file] [log] [blame]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"encoding/json"
"io"
"log"
"testing"
"github.com/stretchr/testify/assert"
"go.chromium.org/chromiumos/config/go/test/api"
testapi "go.chromium.org/chromiumos/config/go/test/lab/api"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
)
func GenerateInternalTestPlan(builDepsTest1 []*api.TestCase_BuildDeps, buildDepsTest2 []*api.TestCase_BuildDeps) *api.InternalTestplan {
nissa := &testapi.Dut_ChromeOS{DutModel: &testapi.DutModel{
BuildTarget: "nissa",
ModelName: "craaskov",
}}
octopus := &testapi.Dut_ChromeOS{DutModel: &testapi.DutModel{
BuildTarget: "octopus",
ModelName: "bluebird",
}}
dedede := &testapi.Dut_ChromeOS{DutModel: &testapi.DutModel{
BuildTarget: "dedede",
ModelName: "crota",
}}
android := &testapi.Dut_Android{DutModel: &testapi.DutModel{
BuildTarget: "android",
ModelName: "android",
}}
internalTestPlan := &api.InternalTestplan{
TestCases: []*api.CTPTestCase{
{
Name: "test1",
Metadata: &api.TestCaseMetadata{
TestCase: &api.TestCase{
Id: &api.TestCase_Id{
Value: "test1",
},
BuildDependencies: builDepsTest1,
},
},
HwRequirements: []*api.HWRequirements{
{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Chromeos{Chromeos: octopus},
},
},
},
},
{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Chromeos{Chromeos: nissa},
},
},
},
},
{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Android_{Android: android},
},
},
},
},
},
},
{
Name: "test2",
Metadata: &api.TestCaseMetadata{
TestCase: &api.TestCase{
Id: &api.TestCase_Id{
Value: "test2",
},
BuildDependencies: buildDepsTest2,
},
},
HwRequirements: []*api.HWRequirements{
{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Chromeos{Chromeos: dedede},
},
},
},
},
},
},
},
SuiteInfo: &api.SuiteInfo{
SuiteMetadata: &api.SuiteMetadata{
TargetRequirements: []*api.TargetRequirements{
{
HwRequirements: &api.HWRequirements{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Chromeos{Chromeos: nissa},
},
},
},
},
SwRequirement: &api.LegacySW{
Build: "release",
GcsPath: "gs://chromeos-image-archive/nissa-release/R124-15808.0.0",
KeyValues: []*api.KeyValue{
{
Key: "chromeos_build",
Value: "nissa-release/R124-15808.0.0",
},
},
},
},
{
HwRequirements: &api.HWRequirements{
HwDefinition: []*api.SwarmingDefinition{
{
DutInfo: &testapi.Dut{
DutType: &testapi.Dut_Chromeos{Chromeos: octopus},
},
},
},
},
SwRequirement: &api.LegacySW{
Build: "release",
GcsPath: "gs://chromeos-image-archive/octopus-release/R124-15810.0.0",
KeyValues: []*api.KeyValue{
{
Key: "chromeos_build",
Value: "nissa-release/R124-15808.0.0",
},
},
},
},
},
},
SuiteRequest: &api.SuiteRequest{
SuiteRequest: &api.SuiteRequest_TestSuite{
TestSuite: &api.TestSuite{
Name: "bluetooth",
Spec: &api.TestSuite_TestCaseTagCriteria_{
TestCaseTagCriteria: &api.TestSuite_TestCaseTagCriteria{
Tags: []string{"suite:bluetooth"},
},
},
},
},
MaximumDuration: durationpb.New(142200),
TestArgs: "None",
AnalyticsName: "Bluetooth_Stable_Nightly",
},
},
}
return internalTestPlan
}
func GenerateBoardUseFlagDict(boardsToAdd []string) map[string]map[string]bool {
useFlagDict := make(map[string]map[string]bool)
useFlagsForNissa := []string{
"common", "nissa",
}
useFlagsForOctopus := []string{
"common", "octopus",
}
useFlagsForDedede := []string{
"common", "dedede",
}
nissaSet := make(map[string]bool)
for _, str := range useFlagsForNissa {
nissaSet[str] = true
}
octopusSet := make(map[string]bool)
for _, str := range useFlagsForOctopus {
octopusSet[str] = true
}
dededeSet := make(map[string]bool)
for _, str := range useFlagsForDedede {
dededeSet[str] = true
}
for _, board := range boardsToAdd {
if board == "nissa" {
useFlagDict["nissa"] = nissaSet
} else if board == "octopus" {
useFlagDict["octopus"] = octopusSet
} else if board == "dedede" {
useFlagDict["dedede"] = dededeSet
}
}
return useFlagDict
}
func JSONSerialize(any interface{}) string {
json, _ := json.Marshal(any)
return string(json)
}
// All test build deps expression qualify. No hwDef removed.
func TestUpdateTestCases_buildDeps_in_use_flags_dict(t *testing.T) {
buildDepsTest1 := []*api.TestCase_BuildDeps{
{
Value: "common,!notpresent",
},
}
internalTestPlan := GenerateInternalTestPlan(buildDepsTest1, buildDepsTest1)
filteredInternalTestPlan := proto.Clone(internalTestPlan).(*api.InternalTestplan)
emptyLogger := log.New(io.Discard, "", 0)
err := updateTestCases(filteredInternalTestPlan, GenerateBoardUseFlagDict([]string{"nissa", "octopus", "dedede"}), emptyLogger)
if err != nil {
t.Errorf("updateTestCases failed: %v", err)
return
}
assert.Equal(t, JSONSerialize(filteredInternalTestPlan), JSONSerialize(internalTestPlan))
}
// Few test build deps expression qualify. Octopus hwDef removed.
func TestUpdateTestCases_buildDeps_in_use_flags_dict_partial_match(t *testing.T) {
buildDepsTest1 := []*api.TestCase_BuildDeps{
{
Value: "nissa,!invalid-use-flag",
},
{
Value: "invalid-use-flag",
},
}
buildDepsTest2 := []*api.TestCase_BuildDeps{
{
Value: "dedede",
},
}
internalTestPlan := GenerateInternalTestPlan(buildDepsTest1, buildDepsTest2)
filteredInternalTestPlan := proto.Clone(internalTestPlan).(*api.InternalTestplan)
emptyLogger := log.New(io.Discard, "", 0)
err := updateTestCases(filteredInternalTestPlan, GenerateBoardUseFlagDict([]string{"octopus", "nissa", "dedede"}), emptyLogger)
if err != nil {
t.Errorf("updateTestCases failed: %v", err)
return
}
for _, testCase := range internalTestPlan.GetTestCases() {
if testCase.GetName() == "test1" {
for _, hwReqs := range testCase.GetHwRequirements() {
var newHwDef []*api.SwarmingDefinition
for _, hwDef := range hwReqs.GetHwDefinition() {
if hwDef.GetDutInfo().GetChromeos() == nil || hwDef.GetDutInfo().GetChromeos().GetDutModel().GetBuildTarget() != "octopus" {
newHwDef = append(newHwDef, hwDef)
}
}
hwReqs.HwDefinition = newHwDef
}
}
}
assert.Equal(t, JSONSerialize(filteredInternalTestPlan), JSONSerialize(internalTestPlan))
}
// No test hwDef expression qualifies. All ChromeOS Dut type hwDef removed.
func TestUpdateTestCases_buildDeps_not_in_use_flags_dict(t *testing.T) {
buildDepsTest1 := []*api.TestCase_BuildDeps{
{
Value: "common,notpresent",
},
{
Value: "!common",
},
}
internalTestPlan := GenerateInternalTestPlan(buildDepsTest1, buildDepsTest1)
filteredInternalTestPlan := proto.Clone(internalTestPlan).(*api.InternalTestplan)
emptyLogger := log.New(io.Discard, "", 0)
err := updateTestCases(filteredInternalTestPlan, GenerateBoardUseFlagDict([]string{"nissa", "octopus", "dedede"}), emptyLogger)
if err != nil {
t.Errorf("updateTestCases failed: %v", err)
return
}
for _, testCase := range internalTestPlan.GetTestCases() {
for _, hwReqs := range testCase.GetHwRequirements() {
var newHwDef []*api.SwarmingDefinition
for _, hwDef := range hwReqs.GetHwDefinition() {
if hwDef.GetDutInfo().GetChromeos() == nil {
newHwDef = append(newHwDef, hwDef)
}
}
hwReqs.HwDefinition = newHwDef
}
}
assert.Equal(t, JSONSerialize(filteredInternalTestPlan), JSONSerialize(internalTestPlan))
}
// Partial test hwDef expression qualifies. No ChromeOS Dut type hwDef removed.
func TestUpdateTestCases_buildDeps_expression_qualifies(t *testing.T) {
buildDepsTest1 := []*api.TestCase_BuildDeps{
{
Value: "common,notpresent",
},
{
Value: "common",
},
}
internalTestPlan := GenerateInternalTestPlan(buildDepsTest1, buildDepsTest1)
filteredInternalTestPlan := proto.Clone(internalTestPlan).(*api.InternalTestplan)
emptyLogger := log.New(io.Discard, "", 0)
err := updateTestCases(filteredInternalTestPlan, GenerateBoardUseFlagDict([]string{"nissa", "octopus", "dedede"}), emptyLogger)
if err != nil {
t.Errorf("updateTestCases failed: %v", err)
return
}
assert.Equal(t, JSONSerialize(filteredInternalTestPlan), JSONSerialize(internalTestPlan))
}
// No use flag dict. All hwDef kept.
func TestUpdateTestCases_use_flag_dict_missing_board(t *testing.T) {
buildDepsTest1 := []*api.TestCase_BuildDeps{
{
Value: "uncommon",
},
}
internalTestPlan := GenerateInternalTestPlan(buildDepsTest1, buildDepsTest1)
filteredInternalTestPlan := proto.Clone(internalTestPlan).(*api.InternalTestplan)
emptyLogger := log.New(io.Discard, "", 0)
err := updateTestCases(filteredInternalTestPlan, GenerateBoardUseFlagDict([]string{""}), emptyLogger)
if err != nil {
t.Errorf("updateTestCases failed: %v", err)
return
}
assert.Equal(t, JSONSerialize(filteredInternalTestPlan), JSONSerialize(internalTestPlan))
}