19190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake# Copyright 2016 The Chromium OS Authors. All rights reserved.
29190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake# Use of this source code is governed by a BSD-style license that can be
39190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake# found in the LICENSE file.
49190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
59190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakeimport json
69190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakeimport logging
79190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakeimport os
89190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
99190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.client.common_lib import error
109190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.client.common_lib import global_config
119190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.client.common_lib.cros import dev_server
129190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.server import adb_utils
139190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.server import constants
149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.server.cros import dnsname_mangler
159190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakefrom autotest_lib.server.hosts import adb_host
169190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
179190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeDEFAULT_ACTS_INTERNAL_DIRECTORY = 'tools/test/connectivity/acts'
189190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
199190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeCONFIG_FOLDER_LOCATION = global_config.global_config.get_config_value(
20a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan    'ACTS', 'acts_config_folder', default='')
219190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
229190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeTEST_DIR_NAME = 'tests'
239190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeFRAMEWORK_DIR_NAME = 'framework'
249190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeSETUP_FILE_NAME = 'setup.py'
259190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeCONFIG_DIR_NAME = 'autotest_config'
269190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeCAMPAIGN_DIR_NAME = 'autotest_campaign'
279190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeLOG_DIR_NAME = 'logs'
289190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeACTS_EXECUTABLE_IN_FRAMEWORK = 'acts/bin/act.py'
299190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
309190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeACTS_TESTPATHS_ENV_KEY = 'ACTS_TESTPATHS'
319190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeACTS_LOGPATH_ENV_KEY = 'ACTS_LOGPATH'
329190a1326eab9dd70406d0fff3988466f4c888b2Benny PeakeACTS_PYTHONPATH_ENV_KEY = 'PYTHONPATH'
339190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
349190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
359190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakedef create_acts_package_from_current_artifact(test_station, job_repo_url,
369190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                              target_zip_file):
379190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """Creates an acts package from the build branch being used.
389190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
399190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    Creates an acts artifact from the build branch being used. This is
409190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    determined by the job_repo_url passed in.
419190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
429190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param test_station: The teststation that should be creating the package.
439190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param job_repo_url: The job_repo_url to get the build info from.
449190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param target_zip_file: The zip file to create form the artifact on the
459190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                            test_station.
469190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
479190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @returns An ActsPackage containing all the information about the zipped
489190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake             artifact.
499190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """
509190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    build_info = adb_host.ADBHost.get_build_info_from_build_url(job_repo_url)
519190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
529190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    return create_acts_package_from_artifact(
53a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        test_station, build_info['branch'], build_info['target'],
54a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        build_info['build_id'], job_repo_url, target_zip_file)
559190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
569190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
579190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakedef create_acts_package_from_artifact(test_station, branch, target, build_id,
589190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                      job_repo_url, target_zip_file):
599190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """Creates an acts package from a specified branch.
609190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
619190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    Grabs the packaged acts artifact from the branch and places it on the
629190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    test_station.
639190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
649190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param test_station: The teststation that should be creating the package.
659190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param branch: The name of the branch where the artifact is to be pulled.
669190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param target: The name of the target where the artifact is to be pulled.
679190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param build_id: The build id to pull the artifact from.
689190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param job_repo_url: The job repo url for where to pull build from.
699190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param target_zip_file: The zip file to create on the teststation.
709190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
719190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @returns An ActsPackage containing all the information about the zipped
729190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake             artifact.
739190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """
749190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    devserver_url = dev_server.AndroidBuildServer.get_server_url(job_repo_url)
759190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    devserver = dev_server.AndroidBuildServer(devserver_url)
76a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan    devserver.trigger_download(
77a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        target, build_id, branch, files='acts.zip', synchronous=True)
789190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
79d6ac897f46fa85e88f727c73490273556a4ad798Benny Peake    pull_base_url = devserver.get_pull_url(target, build_id, branch)
80d6ac897f46fa85e88f727c73490273556a4ad798Benny Peake    download_ulr = os.path.join(pull_base_url, 'acts.zip')
819190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
829190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    test_station.download_file(download_ulr, target_zip_file)
839190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
849190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    return ActsPackage(test_station, target_zip_file)
859190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
869190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
879190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakedef create_acts_package_from_zip(test_station, zip_location, target_zip_file):
889190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """Creates an acts package from an existing zip.
899190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
909190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    Creates an acts package from a zip file that already sits on the drone.
919190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
929190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param test_station: The teststation to create the package on.
939190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param zip_location: The location of the zip on the drone.
949190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @param target_zip_file: The zip file to create on the teststaiton.
959190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
969190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    @returns An ActsPackage containing all the information about the zipped
979190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake             artifact.
989190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """
999190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    if not os.path.isabs(zip_location):
1009190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        zip_location = os.path.join(CONFIG_FOLDER_LOCATION, 'acts_artifacts',
1019190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                    zip_location)
1029190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
10333fb5ffd979a9d00c42a74b88e73697feaeba8a7Benny Peake    test_station.send_file(zip_location, target_zip_file)
1049190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
10533fb5ffd979a9d00c42a74b88e73697feaeba8a7Benny Peake    return ActsPackage(test_station, target_zip_file)
1069190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1079190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1089190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakeclass ActsPackage(object):
1099190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """A packaged version of acts on a teststation."""
110a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan
1119190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def __init__(self, test_station, zip_file_path):
1129190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
1139190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param test_station: The teststation this package is on.
1149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param zip_file_path: The path to the zip file on the test station that
1159190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                              holds the package on the teststation.
1169190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
1179190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.test_station = test_station
1189190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.zip_file = zip_file_path
1199190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1209190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def create_container(self,
1219190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                         container_directory,
1229190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                         internal_acts_directory=None):
1239190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Unpacks this package into a container.
1249190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1259519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        Unpacks this acts package into a container to interact with acts.
1269190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1279190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param container_directory: The directory on the teststation to hold
1289190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                    the container.
1299190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param internal_acts_directory: The directory inside of the package
1309190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                        that holds acts.
1319190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1329190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: An ActsContainer with info on the unpacked acts container.
1339190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
1349519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.test_station.run('unzip "%s" -x -d "%s"' %
1359519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                              (self.zip_file, container_directory))
1369519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
137a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        return ActsContainer(
138a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            self.test_station,
139a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            container_directory,
140a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            acts_directory=internal_acts_directory)
1419519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
1429519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    def create_enviroment(self,
1439519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                          container_directory,
1449519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                          testbed,
1459519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                          testbed_name=None,
1469519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                          internal_acts_directory=None):
1479519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """Unpacks this package into an acts testing enviroment.
1489519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
1499519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        Unpacks this acts package into a test enviroment to test with acts.
1509519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
1519519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param container_directory: The directory on the teststation to hold
1529519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                    the test enviroment.
1539519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param testbed: The testbed that the test enviroment
1549519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                        will be testing on.
1559519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param testbed_name: An overriding name for the testbed.
1569519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param internal_acts_directory: The directory inside of the package
1579519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                        that holds acts.
1589519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
1599519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @returns: An ActsTestingEnviroment with info on the unpacked
1609519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                  acts testing enviroment.
1619519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """
162591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        if testbed.teststation != self.test_station:
163591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            raise error.TestError('Creating a contianer for a testbed on a '
164a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                  'different teststation is not allowed.')
165591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
1669190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.test_station.run('unzip "%s" -x -d "%s"' %
1679190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                              (self.zip_file, container_directory))
1689190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
169a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        return ActsTestingEnviroment(
170a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            testbed=testbed,
171a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            container_directory=container_directory,
172a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            testbed_name=testbed_name,
173a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            acts_directory=internal_acts_directory)
1749190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
1759190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
176591cff492c1d31debfb7d44723a5d382e22b132bBenny Peakeclass AndroidTestingEnviroment(object):
177591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake    """A container for testing android devices on a test station."""
178a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan
1799519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    def __init__(self, testbed, testbed_name=None):
180591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        """Creates a new android testing enviroment.
181591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
182591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        @param testbed: The testbed to test on.
183591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        @param testbed_name: An overriding name for the testbed.
184591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        """
185591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        self.testbed = testbed
186591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
187591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        if not testbed_name:
188591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            # If no override is given get the name from the hostname.
189591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            hostname = testbed.hostname
190591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            if dnsname_mangler.is_ip_address(hostname):
191591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake                testbed_name = hostname
192591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            else:
193591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake                testbed_name = hostname.split('.')[0]
194591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
195591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        self.testbed_name = testbed_name
196591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
197ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake    def install_sl4a_apk(self, force_reinstall=True):
198ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake        """Install sl4a to a test bed.
199ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake
200ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake        @param force_reinstall: If true the apk will be force to reinstall.
201ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake        """
202591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        for serial, adb_host in self.testbed.get_adb_devices().iteritems():
203591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            adb_utils.install_apk_from_build(
204a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                adb_host,
205a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                constants.SL4A_APK,
206a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                constants.SL4A_ARTIFACT,
207ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake                package_name=constants.SL4A_PACKAGE,
208ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake                force_reinstall=force_reinstall)
209591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
210ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake    def install_apk(self, apk_info, force_reinstall=True):
211591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        """Installs an additional apk on all adb devices.
2122573fae61e5f6a4d2809ac21630da7c625711088Benny Peake
2132573fae61e5f6a4d2809ac21630da7c625711088Benny Peake        @param apk_info: A dictionary contianing the apk info. This dictionary
2142573fae61e5f6a4d2809ac21630da7c625711088Benny Peake                         should contain the keys:
2152573fae61e5f6a4d2809ac21630da7c625711088Benny Peake                            apk="Name of the apk",
2162573fae61e5f6a4d2809ac21630da7c625711088Benny Peake                            package="Name of the package".
2172573fae61e5f6a4d2809ac21630da7c625711088Benny Peake                            artifact="Name of the artifact", if missing
2182573fae61e5f6a4d2809ac21630da7c625711088Benny Peake                                      the package name is used."
219ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake        @param force_reinstall: If true the apk will be forced to reinstall.
220591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        """
221591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake        for serial, adb_host in self.testbed.get_adb_devices().iteritems():
222591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake            adb_utils.install_apk_from_build(
223a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                adb_host,
224a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                apk_info['apk'],
225a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                apk_info.get('artifact') or constants.SL4A_ARTIFACT,
226ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake                package_name=apk_info['package'],
227ccac2d18550a9c5d2c43545da73f4f6f6b398d60Benny Peake                force_reinstall=force_reinstall)
228591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
229591cff492c1d31debfb7d44723a5d382e22b132bBenny Peake
2309519ea8471db998eefa54c38508e85d4fa8c1508Benny Peakeclass ActsContainer(object):
2319519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    """A container for working with acts."""
232a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan
233a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan    def __init__(self, test_station, container_directory, acts_directory=None):
2349190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
2359519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param test_station: The test station that the container is on.
2369190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param container_directory: The directory on the teststation this
2379190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                    container operates out of.
2389190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param acts_directory: The directory within the container that holds
2399190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                               acts. If none then it defaults to
2409190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                               DEFAULT_ACTS_INTERNAL_DIRECTORY.
2419190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
2429519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.test_station = test_station
2439519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.container_directory = container_directory
2449190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2459190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not acts_directory:
2469190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            acts_directory = DEFAULT_ACTS_INTERNAL_DIRECTORY
2479190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2489190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not os.path.isabs(acts_directory):
2499190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            self.acts_directory = os.path.join(container_directory,
2509190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                               acts_directory)
2519190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        else:
2529190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            self.acts_directory = acts_directory
2539190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2549190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.tests_directory = os.path.join(self.acts_directory, TEST_DIR_NAME)
2559190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.framework_directory = os.path.join(self.acts_directory,
2569190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                                FRAMEWORK_DIR_NAME)
2579190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2589190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.acts_file = os.path.join(self.framework_directory,
2599190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                      ACTS_EXECUTABLE_IN_FRAMEWORK)
2609190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2619190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.setup_file = os.path.join(self.framework_directory,
2629190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                       SETUP_FILE_NAME)
2639190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2649190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def get_test_paths(self):
2659190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Get all test paths within this container.
2669190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2679190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Gets all paths that hold tests within the container.
2689190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2699190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: A list of paths on the teststation that hold tests.
2709190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
2719190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        get_test_paths_result = self.test_station.run('find %s -type d' %
2729190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                                                      self.tests_directory)
2739190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        test_search_dirs = get_test_paths_result.stdout.splitlines()
2749190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        return test_search_dirs
2759190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2769190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def get_python_path(self):
2779190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Get the python path being used.
2789190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2799190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Gets the python path that will be set in the enviroment for this
2809190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        container.
2819190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2829190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: A string of the PYTHONPATH enviroment variable to be used.
2839190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
2849190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        return '%s:$PYTHONPATH' % self.framework_directory
2859190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2869190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def get_enviroment(self):
2879190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Gets the enviroment variables to be used for this container.
2889190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2899190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: A dictionary of enviroment variables to be used by this
2909190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                  container.
2919190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
292a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        env = {
293a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            ACTS_TESTPATHS_ENV_KEY: ':'.join(self.get_test_paths()),
294a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            ACTS_LOGPATH_ENV_KEY: self.log_directory,
295a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            ACTS_PYTHONPATH_ENV_KEY: self.get_python_path()
296a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        }
2979190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
2989190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        return env
2999190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3009190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def upload_file(self, src, dst):
3019190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Uploads a file to be used by the container.
3029190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3039190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Uploads a file from the drone to the test staiton to be used by the
3049190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        test container.
3059190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3069190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param src: The source file on the drone. If a relative path is given
3079190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                    it is assumed to exist in CONFIG_FOLDER_LOCATION.
3089190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param dst: The destination on the teststation. If a relative path is
3099190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                    given it is assumed that it is within the container.
3109190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3119190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: The full path on the teststation.
3129190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
3139190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not os.path.isabs(src):
3149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            src = os.path.join(CONFIG_FOLDER_LOCATION, src)
3159190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3169190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not os.path.isabs(dst):
3179190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            dst = os.path.join(self.container_directory, dst)
3189190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
319f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake        path = os.path.dirname(dst)
320a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        result = self.test_station.run('mkdir "%s"' % path, ignore_status=True)
321f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake
322f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake        original_dst = dst
323f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake        if os.path.basename(src) == os.path.basename(dst):
324f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake            dst = os.path.dirname(dst)
3259190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3269190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.test_station.send_file(src, dst)
3279190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
328f1b9f3932748bbdb20f07cb90cfade4338098ad2Benny Peake        return original_dst
3299190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3309519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    def setup_enviroment(self, python_bin='python'):
3319519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """Sets up the teststation system enviroment so the container can run.
3329519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3339519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        Prepares the remote system so that the container can run. This involves
3349519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        uninstalling all versions of acts for the version of python being
3359519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        used and installing all needed dependencies.
3369519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3379519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param python_bin: The python binary to use.
3389519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """
3399519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        uninstall_command = '%s %s uninstall' % (python_bin, self.setup_file)
3409519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        install_deps_command = '%s %s install_deps' % (python_bin,
3419519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                                       self.setup_file)
3429519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3439519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.test_station.run(uninstall_command)
3449519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.test_station.run(install_deps_command)
3459519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3469519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3479519ea8471db998eefa54c38508e85d4fa8c1508Benny Peakeclass ActsTestingEnviroment(ActsContainer, AndroidTestingEnviroment):
3489519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    """A container for running acts tests with a contained version of acts."""
349a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan
3509519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake    def __init__(self,
3519519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                 container_directory,
3529519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                 testbed,
3539519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                 testbed_name=None,
3549519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                 acts_directory=None):
3559519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """
3569519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param testbed: The testbed to test on.
3579519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param container_directory: The directory on the teststation this
3589519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                    container operates out of.
3599519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param testbed_name: An overriding name for the testbed.
3609519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        @param acts_directory: The directory within the container that holds
3619519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                               acts. If none then it defaults to
3629519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                               DEFAULT_ACTS_INTERNAL_DIRECTORY.
3639519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        """
364a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        AndroidTestingEnviroment.__init__(
365a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            self, testbed, testbed_name=testbed_name)
3669519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
367a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        ActsContainer.__init__(
368a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            self,
369a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            testbed.teststation,
370a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            container_directory=container_directory,
371a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            acts_directory=acts_directory)
3729519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3739519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.config_location = os.path.join(self.container_directory,
3749519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                            CONFIG_DIR_NAME)
3759519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3769519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.log_directory = os.path.join(self.container_directory,
3779519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                          LOG_DIR_NAME)
3789519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3799519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.acts_file = os.path.join(self.framework_directory,
3809519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                      ACTS_EXECUTABLE_IN_FRAMEWORK)
3819519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3829519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.working_directory = os.path.join(container_directory,
3839519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake                                              CONFIG_DIR_NAME)
3849519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.test_station.run('mkdir %s' % self.working_directory,
385a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                              ignore_status=True)
3869519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3879519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.configs = {}
3889519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake        self.campaigns = {}
3899519ea8471db998eefa54c38508e85d4fa8c1508Benny Peake
3909190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def upload_config(self, config_file):
3919190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Uploads a config file to the container.
3929190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3939190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Uploads a config file to the config folder in the container.
3949190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3959190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param config_file: The config file to upload. This must be a file
3969190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                            within the autotest_config directory under the
3979190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                            CONFIG_FOLDER_LOCATION.
3989190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
3999190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: The full path of the config on the test staiton.
4009190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
4019190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_name = os.path.join(CONFIG_DIR_NAME, config_file)
4029190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4039190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_path = self.upload_file(full_name, full_name)
4049190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.configs[config_file] = full_path
4059190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4069190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        return full_path
4079190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4089190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def upload_campaign(self, campaign_file):
4099190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Uploads a campaign file to the container.
4109190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4119190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Uploads a campaign file to the campaign folder in the container.
4129190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4139190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param campaign_file: The campaign file to upload. This must be a file
4149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                              within the autotest_campaign directory under the
4159190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                              CONFIG_FOLDER_LOCATION.
4169190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4179190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: The full path of the campaign on the test staiton.
4189190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
4199190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_name = os.path.join(CAMPAIGN_DIR_NAME, campaign_file)
4209190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4219190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_path = self.upload_file(full_name, full_name)
4229190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.campaigns[campaign_file] = full_path
4239190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4249190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        return full_path
4259190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4269190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def run_test(self,
4279190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 config,
4289190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 campaign=None,
4299190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 test_case=None,
4309190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 extra_env={},
4319190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 python_bin='python',
432a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                 timeout=7200,
433a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                 additional_cmd_line_params=None):
4349190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Runs a test within the container.
4359190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4369190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        Runs a test within a container using the given settings.
4379190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4389190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param config: The name of the config file to use as the main config.
4399190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                       This should have already been uploaded with
4409190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                       upload_config. The string passed into upload_config
4419190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                       should be used here.
4429190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param campaign: The campaign file to use for this test. If none then
4439190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                         test_case is assumed. This file should have already
4449190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                         been uploaded with upload_campaign. The string passed
4459190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                         into upload_campaign should be used here.
4469190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param test_case: The test case to run the test with. If none then the
447913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake                          campaign will be used. If multiple are given,
448913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake                          multiple will be run.
4499190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param extra_env: Extra enviroment variables to run the test with.
4509190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param python_bin: The python binary to execute the test with.
4519190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param timeout: How many seconds to wait before timing out.
452a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        @param additional_cmd_line_params: Adds the ability to add any string
453a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                           to the end of the acts.py command
454a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                           line string.  This is intended to
455a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                           add acts command line flags however
456a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                           this is unbounded so it could cause
457a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                                           errors if incorrectly set.
4589190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4599190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @returns: The results of the test run.
4609190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
4619190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not config in self.configs:
4629190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            # Check if the config has been uploaded and upload if it hasn't
4639190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            self.upload_config(config)
4649190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4659190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_config = self.configs[config]
4669190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4679190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if campaign:
4689190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            # When given a campaign check if it's upload.
4699190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            if not campaign in self.campaigns:
4709190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                self.upload_campaign(campaign)
4719190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4729190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            full_campaign = self.campaigns[campaign]
4739190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        else:
4749190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            full_campaign = None
4759190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4769190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_env = self.get_enviroment()
4779190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4789190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        # Setup enviroment variables.
4799190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if extra_env:
4809190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            for k, v in extra_env.items():
4819190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                full_env[k] = extra_env
4829190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4839190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        logging.info('Using env: %s', full_env)
4849190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        exports = ('export %s=%s' % (k, v) for k, v in full_env.items())
4859190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        env_command = ';'.join(exports)
4869190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4879190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        # Make sure to execute in the working directory.
4889190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        command_setup = 'cd %s' % self.working_directory
4899190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
490a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        if additional_cmd_line_params:
491a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            act_base_cmd = '%s %s -c %s -tb %s %s ' % (
492a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                python_bin, self.acts_file, full_config, self.testbed_name,
493a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                additional_cmd_line_params)
494a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        else:
495a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            act_base_cmd = '%s %s -c %s -tb %s ' % (
496a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                python_bin, self.acts_file, full_config, self.testbed_name)
4979190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
4989190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        # Format the acts command based on what type of test is being run.
4999190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if test_case and campaign:
5009190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            raise error.TestError(
501a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan                'campaign and test_file cannot both have a value.')
5029190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        elif test_case:
503913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            if isinstance(test_case, str):
504913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake                test_case = [test_case]
505913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            if len(test_case) < 1:
506913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake                raise error.TestError('At least one test case must be given.')
507913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake
508913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            tc_str = ''
509913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            for tc in test_case:
510913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake                tc_str = '%s %s' % (tc_str, tc)
511913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            tc_str = tc_str.strip()
512913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake
513913791f8d6e79e8f5f0f645b3e3793f51b71185fBenny Peake            act_cmd = '%s -tc %s' % (act_base_cmd, tc_str)
5149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        elif campaign:
5159190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            act_cmd = '%s -tf %s' % (act_base_cmd, full_campaign)
5169190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        else:
5179190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            raise error.TestFail('No tests was specified!')
5189190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5199190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        # Format all commands into a single command.
5209190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        command_list = [command_setup, env_command, act_cmd]
5219190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        full_command = '; '.join(command_list)
5229190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5239190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        try:
5249190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            # Run acts on the remote machine.
5259190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            act_result = self.test_station.run(full_command, timeout=timeout)
5269190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            excep = None
5279190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        except Exception as e:
5289190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            # Catch any error to store in the results.
5299190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            act_result = None
5309190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            excep = e
5319190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
532a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan        return ActsTestResults(
533a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            str(test_case) or campaign,
534a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            self.testbed,
535a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            testbed_name=self.testbed_name,
536a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            run_result=act_result,
537a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            log_directory=self.log_directory,
538a0db27cea336604e330ce02e1011a00c760f8157Joe Brennan            exception=excep)
5399190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5409190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5419190a1326eab9dd70406d0fff3988466f4c888b2Benny Peakeclass ActsTestResults(object):
5429190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    """The packaged results of a test run."""
5439190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    acts_result_to_autotest = {
5449190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        'PASS': 'GOOD',
5459190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        'FAIL': 'FAIL',
5469190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        'UNKNOWN': 'WARN',
5479190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        'SKIP': 'ABORT'
5489190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    }
5499190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5509190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def __init__(self,
5519190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 name,
5529190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 testbed,
5539190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 testbed_name=None,
5549190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 run_result=None,
55551c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                 log_directory=None,
5569190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                 exception=None):
5579190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
5589190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param name: A name to identify the test run.
5599190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param testbed: The testbed that ran the test.
5609190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param testbed_name: The name the testbed was run with, if none the
5619190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                             default name of the testbed is used.
5629190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param run_result: The raw i/o result of the test run.
56351c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        @param log_directory: The directory that acts logged to.
5649190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param exception: An exception that was thrown while running the test.
5659190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
5669190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.name = name
5679190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.run_result = run_result
5689190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.exception = exception
56951c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        self.log_directory = log_directory
57051c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        self.test_station = testbed.teststation
5719190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5729190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.testbed = testbed
5739190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not testbed_name:
5749190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            # If no override is given get the name from the hostname.
5759190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            hostname = testbed.hostname
5769190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            if dnsname_mangler.is_ip_address(hostname):
5779190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                self.testbed_name = hostname
5789190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            else:
5799190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                self.testbed_name = hostname.split('.')[0]
5809190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        else:
5819190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            self.testbed_name = testbed_name
5829190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
5839190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.reported_to = set()
5849190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
58551c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        self.json_results = {}
58651c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        self.results_dir = None
58751c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        if self.log_directory:
58851c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            self.results_dir = os.path.join(self.log_directory,
58951c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                                            self.testbed_name, 'latest')
59051c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            results_file = os.path.join(self.results_dir,
59151c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                                        'test_run_summary.json')
59251c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            cat_log_result = self.test_station.run('cat %s' % results_file,
59351c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                                                   ignore_status=True)
59451c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            if not cat_log_result.exit_status:
59551c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                self.json_results = json.loads(cat_log_result.stdout)
59651c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake
5979190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def log_output(self):
5989190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Logs the output of the test."""
5999190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if self.run_result:
6009190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            logging.debug('ACTS Output:\n%s', self.run_result.stdout)
6019190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
60283904b1ded3752220ee088feecba1571e1e8ad63Benny Peake    def save_test_info(self, test):
60383904b1ded3752220ee088feecba1571e1e8ad63Benny Peake        """Save info about the test.
60483904b1ded3752220ee088feecba1571e1e8ad63Benny Peake
60583904b1ded3752220ee088feecba1571e1e8ad63Benny Peake        @param test: The test to save.
60683904b1ded3752220ee088feecba1571e1e8ad63Benny Peake        """
60783904b1ded3752220ee088feecba1571e1e8ad63Benny Peake        if self.testbed and self:
60883904b1ded3752220ee088feecba1571e1e8ad63Benny Peake            self.testbed.save_info(test.resultsdir)
60983904b1ded3752220ee088feecba1571e1e8ad63Benny Peake
6109190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def rethrow_exception(self):
6119190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Re-throws the exception thrown during the test."""
6129190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if self.exception:
6139190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            raise self.exception
6149190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
61551c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake    def upload_to_local(self, local_dir):
61651c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        """Saves all acts results to a local directory.
6179190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
61851c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        @param local_dir: The directory on the local machine to save all results
61951c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake                          to.
6209190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
62151c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        if self.results_dir:
62251c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            self.test_station.get_file(self.results_dir, local_dir)
6239190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
6249190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake    def report_to_autotest(self, test):
6259190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """Reports the results to an autotest test object.
6269190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
62751c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        Reports the results to the test and saves all acts results under the
62851c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        tests results directory.
62951c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake
6309190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        @param test: The autotest test object to report to. If this test object
6319190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                     has already recived our report then this call will be
6329190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake                     ignored.
6339190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        """
6349190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if test in self.reported_to:
6359190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            return
6369190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
63751c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake        if self.results_dir:
63851c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake            self.upload_to_local(test.resultsdir)
63951c675ba15212e58b19fcffb9ff4bfb4031aea46Benny Peake
6409190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        if not 'Results' in self.json_results:
6419190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            return
6429190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
6439190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        results = self.json_results['Results']
6449190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        for result in results:
6459190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            verdict = self.acts_result_to_autotest[result['Result']]
6469190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            details = result['Details']
6479190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake            test.job.record(verdict, None, self.name, status=(details or ''))
6489190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake
6499190a1326eab9dd70406d0fff3988466f4c888b2Benny Peake        self.reported_to.add(test)
650