plumb autotest args from CrosTestRequest into autotest driver

Update run_cros_test.py to have an additionaly autotest_args CLI flag to
align with recent changes to the CrosTestRequest proto. Update the
autotest_driver to plumb this new field into the autotest args when
calling test_that

BUG=b:256691471
TEST=PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python ./run_cros_test.py -host=localhost:2222 -board=zork -tests=tast.generic-list -results=$(pwd)/res -image zork-release.R109-15227.0.0_localchanges -autotest_args tast_list=example.Pass,example.Fail

Cq-Depend: chromium:3997478
Change-Id: I77b4755d29a6c5013084daba4a240bd046010129
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/4004058
Reviewed-by: Derek Beckett <dbeckett@chromium.org>
Commit-Queue: Jack Gelinas <jackgelinas@google.com>
Tested-by: Jack Gelinas <jackgelinas@google.com>
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 5143589..ed1790c 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
@@ -81,7 +81,13 @@
 		libsServer = fmt.Sprintf("%s", primary.LibsServer)
 	}
 
-	args, err := newTautoArgs(primary, companions, testNames, dutServers, resultsDir, libsServer)
+	// Get autotest execution args
+	customAutotestArgs, err := unpackMetadata(req)
+	if err != nil {
+		return nil, err
+	}
+
+	args, err := newTautoArgs(primary, companions, testNames, dutServers, resultsDir, libsServer, customAutotestArgs)
 	if err != nil {
 		return nil, fmt.Errorf("failed to create tauto args: %v", err)
 	}
@@ -162,7 +168,7 @@
 }
 
 // newTautoArgs created an argument structure for invoking tauto
-func newTautoArgs(dut *device.DutInfo, companionDuts []*device.DutInfo, tests, dutServers []string, resultsDir string, libsServer string) (*tautoRunArgs, error) {
+func newTautoArgs(dut *device.DutInfo, companionDuts []*device.DutInfo, tests, dutServers []string, resultsDir string, libsServer string, customAutotestArgs *api.AutotestExecutionMetadata) (*tautoRunArgs, error) {
 	args := tautoRunArgs{
 		target: dut,
 		runFlags: map[string]string{
@@ -190,6 +196,10 @@
 		tautoArgsStr = tautoArgsStr + fmt.Sprintf(" %v=%v", "libs_server", libsServer)
 	}
 
+	for _, customAutotestArg := range customAutotestArgs.GetArgs() {
+		tautoArgsStr = tautoArgsStr + fmt.Sprintf(" %v=%v", customAutotestArg.GetFlag(), customAutotestArg.GetValue())
+	}
+
 	args.runFlags[tautoArgs] = tautoArgsStr
 
 	// Now we need to get a list of all labels, then load the labels const.
@@ -285,6 +295,15 @@
 	return attrMap, labels, nil
 }
 
+// unpackMetadata unpacks the Any metadata field into AutotestExecutionMetadata
+func unpackMetadata(req *api.CrosTestRequest) (*api.AutotestExecutionMetadata, error) {
+	var m api.AutotestExecutionMetadata
+	if err := req.Metadata.UnmarshalTo(&m); err != nil {
+		return nil, fmt.Errorf("improperly formatted input proto metadata, %s", err)
+	}
+	return &m, nil
+}
+
 // genTautoArgList generates argument list for invoking Tauto
 func genTautoArgList(args *tautoRunArgs) (argList []string) {
 	for flag, value := range args.runFlags {
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 c0f31d4..d17b7ea 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
@@ -9,9 +9,9 @@
 	"sort"
 	"testing"
 
-	"github.com/google/go-cmp/cmp"
-
 	"chromiumos/test/execution/cmd/cros-test/internal/device"
+	"github.com/google/go-cmp/cmp"
+	"go.chromium.org/chromiumos/config/go/test/api"
 )
 
 // TestNewTautoArgs makes sure newTautoArgs creates the correct arguments for tauto.
@@ -45,6 +45,14 @@
 		CameraboxFacing:     "front",
 		CableList:           []string{"type:usbaudio"},
 	}
+	customAutotestArgs := &api.AutotestExecutionMetadata{
+		Args: []*api.AutotestExecutionMetadata_Arg{
+			{
+				Flag:  "tast_list",
+				Value: "tast.example.Pass",
+			},
+		},
+	}
 
 	expectedArgs := tautoRunArgs{
 		target:   primary,
@@ -56,7 +64,7 @@
 			dutServerFlag:       "localhost:2222,localhost:2223,localhost:2224",
 			attributes:          `{"servo_host":"127.123.332.121","servo_port":"1337","servo_serial":"8675309"}`,
 			labels:              "board:fred model:flintstone servo chameleon audio_board chameleon:vga chameleon:hdmi atrus mimo camerabox_facing:front type:usbaudio",
-			tautoArgs:           "dut_servers=localhost:2222,localhost:2223,localhost:2224 libs_server=192.168.1.1:8675",
+			tautoArgs:           "dut_servers=localhost:2222,localhost:2223,localhost:2224 libs_server=192.168.1.1:8675 tast_list=tast.example.Pass",
 			libsServerFlag:      "192.168.1.1:8675",
 		},
 		cftFlag: "--CFT",
@@ -64,7 +72,7 @@
 
 	dut := primary
 	tests := []string{test1, test2, test3, test4, test5}
-	args, err := newTautoArgs(dut, companions, tests, dutServers, workDir1, libsServer)
+	args, err := newTautoArgs(dut, companions, tests, dutServers, workDir1, libsServer, customAutotestArgs)
 	if err != nil {
 		t.Errorf("Got err ")
 	}
diff --git a/src/chromiumos/test/python/src/tools/cmd_util.py b/src/chromiumos/test/python/src/tools/cmd_util.py
index 142228a..2020c95 100644
--- a/src/chromiumos/test/python/src/tools/cmd_util.py
+++ b/src/chromiumos/test/python/src/tools/cmd_util.py
@@ -6,6 +6,7 @@
 
 import errno
 import functools
+import logging
 import operator
 import os
 import pathlib
@@ -14,7 +15,7 @@
 import sys
 import tempfile
 import time
-import logging
+
 
 sys.path.insert(1, str(pathlib.Path(__file__).parent.resolve()/'../../'))
 
diff --git a/src/chromiumos/test/python/src/tools/run_cros_test.py b/src/chromiumos/test/python/src/tools/run_cros_test.py
index ce70b0f..866d833 100755
--- a/src/chromiumos/test/python/src/tools/run_cros_test.py
+++ b/src/chromiumos/test/python/src/tools/run_cros_test.py
@@ -15,15 +15,18 @@
 import sys
 import tempfile
 
+from google.protobuf.any_pb2 import Any
 from google.protobuf.json_format import MessageToJson
 
+
 # Used to import the proto stack.
 sys.path.insert(1, str(pathlib.Path(__file__).parent.resolve() / '../../../../../../../../config/python'))
-import chromiumos.test.lab.api.dut_pb2 as lab_protos
-import chromiumos.test.lab.api.ip_endpoint_pb2 as IpEndpoint
 import chromiumos.test.api.cros_test_cli_pb2 as cros_test_request
 import chromiumos.test.api.test_case_pb2 as test_case
+import chromiumos.test.api.test_execution_metadata_pb2 as test_execution_metatdata
 import chromiumos.test.api.test_suite_pb2 as test_suite
+import chromiumos.test.lab.api.dut_pb2 as lab_protos
+import chromiumos.test.lab.api.ip_endpoint_pb2 as IpEndpoint
 
 
 TEST_DIR = os.path.dirname(os.path.realpath(__file__))
@@ -70,6 +73,14 @@
                       dest='host',
                       default='localhost:2222',
                       help='hostname of dut.')
+  parser.add_argument('-autotest_args',
+                      dest='autotest_args',
+                      default='',
+                      nargs='*',
+                      help='Flag/value pairs to pass through to'
+                           'test_that. Note, flags and values must be'
+                           'separated by \'=\' character. '
+                           'e.g. --autotest_args foo=bar cat="in a hat"')
 
   args = parser.parse_args()
   return args
@@ -129,6 +140,7 @@
     # Base docker run command to build from.
     self.args = args
     self.test_request = args.tests.split(',')
+    self.autotest_args = args.autotest_args
     self.harness = args.harness
     self.dutAddr = args.host
     self.image = image
@@ -186,10 +198,22 @@
     """Builds the request proto"""
     dut = self.build_dut_info()
     tests = self.build_test_info()
+    metadata = self.build_metadata_info()
     primary = cros_test_request.CrosTestRequest.Device(dut=dut)
-    f = cros_test_request.CrosTestRequest(primary=primary, test_suites=tests)
+    f = cros_test_request.CrosTestRequest(primary=primary, test_suites=tests, metadata=metadata)
     return f
 
+  def build_metadata_info(self):
+    """Builds the test execution metadata proto"""
+    autotest_args_proto = []
+    for flag_value_pair in self.autotest_args:
+      flag, value = flag_value_pair.split("=", 1)
+      autotest_arg_proto = test_execution_metatdata.AutotestExecutionMetadata.Arg(flag=flag, value=value)
+      autotest_args_proto.append(autotest_arg_proto)
+    metadata = Any()
+    metadata.Pack(test_execution_metatdata.AutotestExecutionMetadata(args=autotest_args_proto))
+    return metadata
+
   def build_test_info(self) -> test_suite.TestSuite:
     """Build the test suite info/proto."""
     test_case_ids = []
diff --git a/src/chromiumos/test/python/src/tools/signals.py b/src/chromiumos/test/python/src/tools/signals.py
index 0e02689..4987616 100644
--- a/src/chromiumos/test/python/src/tools/signals.py
+++ b/src/chromiumos/test/python/src/tools/signals.py
@@ -4,8 +4,8 @@
 
 """Signal related functionality."""
 
-import signal
 import contextlib
+import signal
 
 
 def RelaySignal(handler, signum, frame):
diff --git a/src/chromiumos/test/python/src/tools/test/test_cmd_util.py b/src/chromiumos/test/python/src/tools/test/test_cmd_util.py
index fbc0565..5777512 100644
--- a/src/chromiumos/test/python/src/tools/test/test_cmd_util.py
+++ b/src/chromiumos/test/python/src/tools/test/test_cmd_util.py
@@ -12,6 +12,7 @@
 import unittest
 from unittest import mock
 
+
 sys.path.insert(1, '../../../')
 
 from src.tools import cmd_util