autotest/tast: add varsfiles option in tast class

In order to pass cros_labels to tast tests, this CL adds varsfiles
option for later CLs to use.  Also tast framework has already added an
option |-varsfile| that supports batch key-value variables in yaml
format that could be imported to |testing.State.Var|.

BUG=chromium:1021415,b:143128095
TEST=tast_unittest.py

Change-Id: I2f003bf2d1824fd3ced79297db7ff89d323fd33f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/1958361
Tested-by: Clark Chung <ckclark@chromium.org>
Commit-Queue: Clark Chung <ckclark@chromium.org>
Reviewed-by: Shuhei Takahashi <nya@chromium.org>
diff --git a/server/site_tests/tast/tast.py b/server/site_tests/tast/tast.py
index 4e77206..c40041c 100644
--- a/server/site_tests/tast/tast.py
+++ b/server/site_tests/tast/tast.py
@@ -114,7 +114,7 @@
 
     def initialize(self, host, test_exprs, ignore_test_failures=False,
                    max_run_sec=3600, command_args=[], install_root='/',
-                   run_private_tests=True):
+                   run_private_tests=True, varsfiles=None):
         """
         @param host: remote.RemoteHost instance representing DUT.
         @param test_exprs: Array of strings describing tests to run.
@@ -130,6 +130,8 @@
         @param install_root: Root directory under which Tast binaries are
             installed. Alternate values may be passed by unit tests.
         @param run_private_tests: Download and run private tests.
+        @param varsfiles: list of names of yaml files containing variables set
+            in |-varsfile| arguments.
 
         @raises error.TestFail if the Tast installation couldn't be found.
         """
@@ -141,6 +143,7 @@
         self._install_root = install_root
         self._run_private_tests = run_private_tests
         self._fake_now = None
+        self._varsfiles = varsfiles
 
         # List of JSON objects describing tests that will be run. See Test in
         # src/platform/tast/src/chromiumos/tast/testing/test.go for details.
@@ -360,6 +363,10 @@
             '-continueafterfailure=true',
         ] + self._devserver_args + self._get_servo_args()
 
+        if self._varsfiles:
+            for varsfile in self._varsfiles:
+                args.append('-varsfile=%s' % varsfile)
+
         if self._run_private_tests:
             args.append('-downloadprivatebundles=true')
 
diff --git a/server/site_tests/tast/tast_unittest.py b/server/site_tests/tast/tast_unittest.py
index 69ced24..c804b7c 100755
--- a/server/site_tests/tast/tast_unittest.py
+++ b/server/site_tests/tast/tast_unittest.py
@@ -10,6 +10,7 @@
 import shutil
 import tempfile
 import unittest
+import yaml
 
 import dateutil.parser
 
@@ -118,13 +119,14 @@
                 else tast.tast._REMOTE_TEST_RUNNER_PATH)
 
     def _init_tast_commands(self, tests, run_private_tests=False,
-                            run_vars=[]):
+                            run_vars=[], run_varsfiles=None):
         """Sets fake_tast.py's behavior for 'list' and 'run' commands.
 
         @param tests: List of TestInfo objects.
         @param run_private_tests: Whether to run private tests.
         @param run_vars: List of string values that should be passed to 'run'
             via -var.
+        @param run_varsfiles: filenames should be passed to 'run' via -varsfile.
         """
         list_args = [
             'build=False',
@@ -141,6 +143,8 @@
             'continueafterfailure=True',
             'var=%s' % run_vars,
         ]
+        if run_varsfiles:
+            run_args.append('varsfile=%s' % run_varsfiles)
 
         test_list = json.dumps([t.test() for t in tests])
         run_files = {
@@ -162,7 +166,7 @@
                             tast.tast._STREAMED_RESULTS_FILENAME)
 
     def _run_test(self, ignore_test_failures=False, command_args=[],
-                  run_private_tests=False):
+                  run_private_tests=False, varsfiles=None):
         """Writes fake_tast.py's configuration and runs the test.
 
         @param ignore_test_failures: Passed as the identically-named arg to
@@ -171,6 +175,8 @@
             Tast.initialize().
         @param run_private_tests: Passed as the identically-named arg to
             Tast.initialize().
+        @param varsfiles: list of names of yaml files containing variables set
+             in |-varsfile| arguments.
         """
         self._test.initialize(self._host,
                               self.TEST_PATTERNS,
@@ -178,7 +184,8 @@
                               max_run_sec=self.MAX_RUN_SEC,
                               command_args=command_args,
                               install_root=self._root_dir,
-                              run_private_tests=run_private_tests)
+                              run_private_tests=run_private_tests,
+                              varsfiles=varsfiles)
         self._test.set_fake_now_for_testing(
                 (NOW - tast._UNIX_EPOCH).total_seconds())
 
@@ -514,6 +521,15 @@
         self._host.host_info_store.commit(host_info.HostInfo(attributes=attr))
         self._run_test()
 
+    def testVarsfileOption(self):
+        with tempfile.NamedTemporaryFile(
+                suffix='.yaml', dir=self._temp_dir) as temp_file:
+            yaml.dump({"var1": "val1", "var2": "val2"}, stream=temp_file)
+            varsfiles = [temp_file.name]
+            self._init_tast_commands([TestInfo('pkg.Test', 0, 0)],
+                                     run_varsfiles=varsfiles)
+            self._run_test(varsfiles=varsfiles)
+
 
 class TestInfo:
     """Wraps information about a Tast test.
diff --git a/server/site_tests/tast/testdata/fake_tast.py b/server/site_tests/tast/testdata/fake_tast.py
index c1989ab..2d97e45 100755
--- a/server/site_tests/tast/testdata/fake_tast.py
+++ b/server/site_tests/tast/testdata/fake_tast.py
@@ -111,6 +111,7 @@
                             default=False, nargs='?')
     run_parser.add_argument('-var', action='append', default=[])
     run_parser.add_argument('-defaultvarsdir')
+    run_parser.add_argument('-varsfile', action='append', default=[])
 
     return parser.parse_args()