cros-test: Support companion DUTs
It is the second CL of a chain of CLs to enhance cros-test to support
multi-DUTs.
This CL add code to suport companion DUTs for both Tast & Tauto.
New unit test has been added.
BUG=b:199941891
TEST=./fast_build.sh -T; cros-test --input ...companion.json ....
Change-Id: Iab4188c9633b0b4f8e218b9851e1aee9757b21bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/3216909
Commit-Queue: Seewai Fu <[email protected]>
Tested-by: Seewai Fu <[email protected]>
Reviewed-by: Derek Beckett <[email protected]>
Reviewed-by: Jesse McGuire <[email protected]>
diff --git a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/driver.go b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/driver.go
index d29979e..1f8c9a4 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/driver.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/driver.go
@@ -34,7 +34,7 @@
// Driver provides common interface to execute Tast and Autotest.
type Driver interface {
// RunTests drives a test framework to execute tests.
- RunTests(ctx context.Context, resultsDir string, primary *api.CrosTestRequest_Device, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error)
+ RunTests(ctx context.Context, resultsDir string, req *api.CrosTestRequest, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error)
// Name returns the name of the driver.
Name() string
diff --git a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver.go b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver.go
index b7fd968..78e031d 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver.go
@@ -39,7 +39,10 @@
}
// RunTests drives a test framework to execute tests.
-func (td *TastDriver) RunTests(ctx context.Context, resultsDir string, primary *api.CrosTestRequest_Device, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error) {
+func (td *TastDriver) RunTests(ctx context.Context, resultsDir string, req *api.CrosTestRequest, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error) {
+ primary := req.Primary
+ companions := req.Companions
+
testNamesToIds := getTestNamesToIds(tests)
testNames := getTestNames(tests)
@@ -55,7 +58,16 @@
return nil, errors.NewStatusError(errors.InvalidArgument,
fmt.Errorf("cannot get address from primary device: %v", primary))
}
- args := newTastArgs(addr, testNames, resultsDir, tlwAddr, reportServer.Address())
+ var companionAddrs []string
+ for _, c := range companions {
+ address, err := device.Address(c)
+ if err != nil {
+ return nil, errors.NewStatusError(errors.InvalidArgument,
+ fmt.Errorf("cannot get address from companion device: %v", c))
+ }
+ companionAddrs = append(companionAddrs, address)
+ }
+ args := newTastArgs(addr, companionAddrs, testNames, resultsDir, tlwAddr, reportServer.Address())
// Run tast.
cmd := exec.Command("/usr/bin/tast", genArgList(args)...)
@@ -136,25 +148,28 @@
tlwServerFlag = "-tlwserver"
waitUntilReadyFlag = "-waituntilready"
timeOutFlag = "-timeout"
- keyfile = "-keyfile"
- reportsServer = "-reports_server"
+ keyfileFlag = "-keyfile"
+ reportsServerFlag = "-reports_server"
+ companionDUTFlag = "-companiondut"
)
// runArgs stores arguments to invoke Tast
type runArgs struct {
- target string // The url for the target machine.
- patterns []string // The names of test to be run.
- tastFlags map[string]string // The flags for tast.
- runFlags map[string]string // The flags for tast run command.
+ target string // The url for the target machine.
+ patterns []string // The names of test to be run.
+ tastFlags map[string]string // The flags for tast.
+ runFlags map[string]string // The flags for tast run command.
+ companions []string // The companion DUTs to be used for testing.
}
// newTastArgs created an argument structure for invoking tast
-func newTastArgs(dut string, tests []string, resultsDir, tlwAddress, rsAddress string) *runArgs {
+func newTastArgs(dut string, companionDuts, tests []string, resultsDir, tlwAddress, rsAddress string) *runArgs {
downloadPrivateBundles := "false"
// Change downloadPrivateBundlesFlag to "true" if tlwServer is specified.
if tlwAddress != "" {
downloadPrivateBundles = "true"
}
+
return &runArgs{
target: dut,
tastFlags: map[string]string{
@@ -168,10 +183,11 @@
downloadPrivateBundlesFlag: downloadPrivateBundles,
timeOutFlag: "3000",
resultsDirFlag: resultsDir,
- reportsServer: rsAddress,
+ reportsServerFlag: rsAddress,
tlwServerFlag: tlwAddress,
},
- patterns: tests, // TO-DO Support Tags
+ patterns: tests, // TO-DO Support Tags
+ companions: companionDuts,
}
}
@@ -184,6 +200,10 @@
for flag, value := range args.runFlags {
argList = append(argList, fmt.Sprintf("%v=%v", flag, value))
}
+ for i, c := range args.companions {
+ // example: -companiondut=cd1:127.0.0.1:2222
+ argList = append(argList, fmt.Sprintf("%v=cd%v:%v", companionDUTFlag, i+1, c))
+ }
argList = append(argList, args.target)
argList = append(argList, args.patterns...)
return argList
diff --git a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver_test.go b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver_test.go
index 23e11c0..2697e0a 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver_test.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tast_driver_test.go
@@ -9,6 +9,7 @@
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
)
// TestNewTastArgs makes sure newTastArgs creates the correct arguments for tast.
@@ -27,13 +28,13 @@
downloadPrivateBundlesFlag: "true",
timeOutFlag: "3000",
resultsDirFlag: workDir1,
- reportsServer: ":5555",
+ reportsServerFlag: ":5555",
tlwServerFlag: tlwAddress,
},
}
- args := newTastArgs(dut1, expectedArgs.patterns, workDir1, tlwAddress, expectedArgs.runFlags[reportsServer])
- if diff := cmp.Diff(args, &expectedArgs, cmp.AllowUnexported(runArgs{})); diff != "" {
+ args := newTastArgs(dut1, []string{}, expectedArgs.patterns, workDir1, tlwAddress, expectedArgs.runFlags[reportsServerFlag])
+ if diff := cmp.Diff(args, &expectedArgs, cmp.AllowUnexported(runArgs{}), cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Got unexpected argument from newTastArgs (-got +want):\n%s\n%v\n--\n%v\n", diff, args, expectedArgs)
}
}
@@ -54,12 +55,41 @@
downloadPrivateBundlesFlag: "false",
timeOutFlag: "3000",
resultsDirFlag: workDir1,
- reportsServer: ":5555",
+ reportsServerFlag: ":5555",
tlwServerFlag: "",
},
}
- args := newTastArgs(dut1, expectedArgs.patterns, workDir1, "", expectedArgs.runFlags[reportsServer])
+ args := newTastArgs(dut1, []string{}, expectedArgs.patterns, workDir1, "", expectedArgs.runFlags[reportsServerFlag])
+ if diff := cmp.Diff(args, &expectedArgs, cmp.AllowUnexported(runArgs{}), cmpopts.EquateEmpty()); diff != "" {
+ t.Errorf("Got unexpected argument from newTastArgs (-got +want):\n%s", diff)
+ }
+}
+
+// TestNewTastArgsCompanions makes sure newTastArgs creates the correct arguments for tast with companion DUTs.
+func TestNewTastArgsCompanions(t *testing.T) {
+ companions := []string{"companion_dut1_address", "companion_dut2_address"}
+ expectedArgs := runArgs{
+ target: dut1,
+ patterns: []string{test1, test2, test3, test4, test5},
+ tastFlags: map[string]string{
+ verboseFlag: "true",
+ logTimeFlag: "false",
+ },
+ runFlags: map[string]string{
+ sshRetriesFlag: "2",
+ downloadDataFlag: "batch",
+ buildFlag: "false",
+ downloadPrivateBundlesFlag: "false",
+ timeOutFlag: "3000",
+ resultsDirFlag: workDir1,
+ reportsServerFlag: ":5555",
+ tlwServerFlag: "",
+ },
+ companions: companions,
+ }
+
+ args := newTastArgs(dut1, companions, expectedArgs.patterns, workDir1, "", expectedArgs.runFlags[reportsServerFlag])
if diff := cmp.Diff(args, &expectedArgs, cmp.AllowUnexported(runArgs{})); diff != "" {
t.Errorf("Got unexpected argument from newTastArgs (-got +want):\n%s", diff)
}
@@ -67,6 +97,7 @@
// TestGenArgList makes sure genArgList generates the correct list of argument for tast.
func TestGenArgList(t *testing.T) {
+ companions := []string{"companion_dut1_address", "companion_dut2_address"}
args := runArgs{
target: dut1,
patterns: []string{test1, test2},
@@ -82,8 +113,9 @@
timeOutFlag: "3000",
resultsDirFlag: workDir1,
tlwServerFlag: tlwAddress,
- reportsServer: "127.0.0.1:3333",
+ reportsServerFlag: "127.0.0.1:3333",
},
+ companions: companions,
}
var expectedArgList []string
@@ -95,6 +127,9 @@
for key, value := range args.runFlags {
expectedArgList = append(expectedArgList, fmt.Sprintf("%v=%v", key, value))
}
+ for i, c := range companions {
+ expectedArgList = append(expectedArgList, fmt.Sprintf("%v=cd%v:%v", companionDUTFlag, i+1, c))
+ }
dutIndex := len(expectedArgList)
expectedArgList = append(expectedArgList, dut1)
expectedArgList = append(expectedArgList, test1)
diff --git a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver.go b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver.go
index 4eecaa8..bfba197 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver.go
@@ -11,6 +11,7 @@
"fmt"
"log"
"os/exec"
+ "strings"
"sync"
"chromiumos/lro"
@@ -47,7 +48,9 @@
}
// RunTests drives a test framework to execute tests.
-func (td *TautoDriver) RunTests(ctx context.Context, resultsDir string, primary *api.CrosTestRequest_Device, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error) {
+func (td *TautoDriver) RunTests(ctx context.Context, resultsDir string, req *api.CrosTestRequest, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error) {
+ primary := req.Primary
+ companions := req.Companions
testNamesToIds := getTestNamesToIds(tests)
testNames := getTestNames(tests)
@@ -55,7 +58,15 @@
if err != nil {
return nil, fmt.Errorf("cannot get address from DUT: %v", primary)
}
- args := newTautoArgs(addr, testNames, resultsDir)
+ var companionAddrs []string
+ for _, c := range companions {
+ address, err := device.Address(c)
+ if err != nil {
+ return nil, fmt.Errorf("cannot get address from companion device: %v", c)
+ }
+ companionAddrs = append(companionAddrs, address)
+ }
+ args := newTautoArgs(addr, companionAddrs, testNames, resultsDir)
// Run RTD.
cmd := exec.Command("/usr/bin/test_that", genTautoArgList(args)...)
@@ -106,8 +117,9 @@
// Flag names. More to be populated once impl details are firmed.
const (
- autotestDir = "--autotest_dir"
+ autotestDirFlag = "--autotest_dir"
tautoResultsDirFlag = "--results_dir"
+ companionFlag = "--companion_hosts"
)
// tautoRunArgs stores arguments to invoke tauto
@@ -118,13 +130,17 @@
}
// newTautoArgs created an argument structure for invoking tauto
-func newTautoArgs(dut string, tests []string, resultsDir string) *tautoRunArgs {
+func newTautoArgs(dut string, companions, tests []string, resultsDir string) *tautoRunArgs {
args := tautoRunArgs{
target: dut,
runFlags: map[string]string{
- autotestDir: common.AutotestDir,
+ autotestDirFlag: common.AutotestDir,
},
}
+ if len(companions) > 0 {
+ companionsAddresses := strings.Join(companions, ",")
+ args.runFlags[companionFlag] = companionsAddresses
+ }
args.patterns = tests // TO-DO Support Tags
args.runFlags[tautoResultsDirFlag] = resultsDir
diff --git a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver_test.go b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver_test.go
index 80dcd44..003ddc4 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver_test.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/internal/driver/tauto_driver_test.go
@@ -13,18 +13,20 @@
// TestNewTautoArgs makes sure newTautoArgs creates the correct arguments for tauto.
func TestNewTautoArgs(t *testing.T) {
+ companions := []string{"companion1", "companion2"}
expectedArgs := tautoRunArgs{
target: dut1,
patterns: []string{test1, test2, test3, test4, test5},
runFlags: map[string]string{
tautoResultsDirFlag: workDir1,
- autotestDir: "/usr/local/autotest/",
+ autotestDirFlag: "/usr/local/autotest/",
+ companionFlag: "companion1,companion2",
},
}
dut := dut1
tests := []string{test1, test2, test3, test4, test5}
- args := newTautoArgs(dut, tests, workDir1)
+ args := newTautoArgs(dut, companions, tests, workDir1)
if diff := cmp.Diff(args, &expectedArgs, cmp.AllowUnexported(tautoRunArgs{})); diff != "" {
t.Errorf("Got unexpected argument from newTautoArgs (-got +want):\n%s", diff)
}
@@ -37,7 +39,8 @@
patterns: []string{test1, test2},
runFlags: map[string]string{
tautoResultsDirFlag: workDir1,
- autotestDir: "/usr/local/autotest/",
+ autotestDirFlag: "/usr/local/autotest/",
+ companionFlag: "companion1,companion2",
},
}
diff --git a/src/chromiumos/test/execution/cmd/cros-test/testexecserver.go b/src/chromiumos/test/execution/cmd/cros-test/testexecserver.go
index 76a160b..d7aa750 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/testexecserver.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/testexecserver.go
@@ -70,7 +70,7 @@
return nil, statuserrors.NewStatusError(statuserrors.IOCreateError,
fmt.Errorf("failed to create result directory %v", resultsDir))
}
- rspn, err := driver.RunTests(ctx, resultsDir, req.Primary, tlwAddr, tests)
+ rspn, err := driver.RunTests(ctx, resultsDir, req, tlwAddr, tests)
if err != nil {
return nil, err
}
diff --git a/src/chromiumos/test/execution/cmd/cros-test/testexecserver_test.go b/src/chromiumos/test/execution/cmd/cros-test/testexecserver_test.go
index 39720a6..41f449b 100644
--- a/src/chromiumos/test/execution/cmd/cros-test/testexecserver_test.go
+++ b/src/chromiumos/test/execution/cmd/cros-test/testexecserver_test.go
@@ -56,6 +56,18 @@
},
},
},
+ Companions: []*api.CrosTestRequest_Device{
+ {
+ Dut: &labapi.Dut{
+ Id: &labapi.Dut_Id{Value: "CompanionDut1"},
+ DutType: &labapi.Dut_Chromeos{
+ Chromeos: &labapi.Dut_ChromeOS{
+ Ssh: &labapi.IpEndpoint{Address: "127.0.0.1", Port: 2223},
+ },
+ },
+ },
+ },
+ },
}
m := jsonpb.Marshaler{}
diff --git a/src/chromiumos/test/execution/data/companions.json b/src/chromiumos/test/execution/data/companions.json
new file mode 100644
index 0000000..bf68648
--- /dev/null
+++ b/src/chromiumos/test/execution/data/companions.json
@@ -0,0 +1,38 @@
+{
+ "test_suites" : [
+ {
+ "name" : "suite1",
+ "test_case_ids" : {
+ "test_case_ids" : [
+ {
+ "value" : "tast.meta.CompanionDUTs"
+ }
+ ]
+ }
+ }
+ ],
+ "primary":{
+ "dut":{
+ "id":{"value":"primary_dut"},
+ "chromeos":{
+ "ssh":{
+ "address":"127.0.0.1",
+ "port":2222
+ }
+ }
+ }
+ },
+ "companions":[
+ {
+ "dut": {
+ "id": {"value":"CompanionDut1"},
+ "chromeos": {
+ "ssh":{
+ "address":"127.0.0.1",
+ "port":2223
+ }
+ }
+ }
+ }
+ ]
+}