blob: 2d832d2ce4f46c24366b9fc048e29057c131ba79 [file] [log] [blame]
Benny Peake9190a132016-11-02 12:57:01 -07001# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Benny Peake9190a132016-11-02 12:57:01 -07005import json
6import logging
7import os
8
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.common_lib import global_config
11from autotest_lib.client.common_lib.cros import dev_server
12from autotest_lib.server import adb_utils
13from autotest_lib.server import constants
14from autotest_lib.server.cros import dnsname_mangler
15from autotest_lib.server.hosts import adb_host
16from autotest_lib.site_utils import sponge_utils
17
18DEFAULT_ACTS_INTERNAL_DIRECTORY = 'tools/test/connectivity/acts'
19
20CONFIG_FOLDER_LOCATION = global_config.global_config.get_config_value(
Joe Brennana0db27c2017-02-27 15:40:00 -080021 'ACTS', 'acts_config_folder', default='')
Benny Peake9190a132016-11-02 12:57:01 -070022
23TEST_DIR_NAME = 'tests'
24FRAMEWORK_DIR_NAME = 'framework'
25SETUP_FILE_NAME = 'setup.py'
26CONFIG_DIR_NAME = 'autotest_config'
27CAMPAIGN_DIR_NAME = 'autotest_campaign'
28LOG_DIR_NAME = 'logs'
29ACTS_EXECUTABLE_IN_FRAMEWORK = 'acts/bin/act.py'
30
31ACTS_TESTPATHS_ENV_KEY = 'ACTS_TESTPATHS'
32ACTS_LOGPATH_ENV_KEY = 'ACTS_LOGPATH'
33ACTS_PYTHONPATH_ENV_KEY = 'PYTHONPATH'
34
35
36def create_acts_package_from_current_artifact(test_station, job_repo_url,
37 target_zip_file):
38 """Creates an acts package from the build branch being used.
39
40 Creates an acts artifact from the build branch being used. This is
41 determined by the job_repo_url passed in.
42
43 @param test_station: The teststation that should be creating the package.
44 @param job_repo_url: The job_repo_url to get the build info from.
45 @param target_zip_file: The zip file to create form the artifact on the
46 test_station.
47
48 @returns An ActsPackage containing all the information about the zipped
49 artifact.
50 """
51 build_info = adb_host.ADBHost.get_build_info_from_build_url(job_repo_url)
52
53 return create_acts_package_from_artifact(
Joe Brennana0db27c2017-02-27 15:40:00 -080054 test_station, build_info['branch'], build_info['target'],
55 build_info['build_id'], job_repo_url, target_zip_file)
Benny Peake9190a132016-11-02 12:57:01 -070056
57
58def create_acts_package_from_artifact(test_station, branch, target, build_id,
59 job_repo_url, target_zip_file):
60 """Creates an acts package from a specified branch.
61
62 Grabs the packaged acts artifact from the branch and places it on the
63 test_station.
64
65 @param test_station: The teststation that should be creating the package.
66 @param branch: The name of the branch where the artifact is to be pulled.
67 @param target: The name of the target where the artifact is to be pulled.
68 @param build_id: The build id to pull the artifact from.
69 @param job_repo_url: The job repo url for where to pull build from.
70 @param target_zip_file: The zip file to create on the teststation.
71
72 @returns An ActsPackage containing all the information about the zipped
73 artifact.
74 """
75 devserver_url = dev_server.AndroidBuildServer.get_server_url(job_repo_url)
76 devserver = dev_server.AndroidBuildServer(devserver_url)
Joe Brennana0db27c2017-02-27 15:40:00 -080077 devserver.trigger_download(
78 target, build_id, branch, files='acts.zip', synchronous=True)
Benny Peake9190a132016-11-02 12:57:01 -070079
80 download_ulr = os.path.join(job_repo_url, 'acts.zip')
81
82 test_station.download_file(download_ulr, target_zip_file)
83
84 return ActsPackage(test_station, target_zip_file)
85
86
87def create_acts_package_from_zip(test_station, zip_location, target_zip_file):
88 """Creates an acts package from an existing zip.
89
90 Creates an acts package from a zip file that already sits on the drone.
91
92 @param test_station: The teststation to create the package on.
93 @param zip_location: The location of the zip on the drone.
94 @param target_zip_file: The zip file to create on the teststaiton.
95
96 @returns An ActsPackage containing all the information about the zipped
97 artifact.
98 """
99 if not os.path.isabs(zip_location):
100 zip_location = os.path.join(CONFIG_FOLDER_LOCATION, 'acts_artifacts',
101 zip_location)
102
103 remote_zip = test_station.send_file(zip_location, target_zip_file)
104
105 return ActsPackage(test_station, remote_zip)
106
107
108class ActsPackage(object):
109 """A packaged version of acts on a teststation."""
Joe Brennana0db27c2017-02-27 15:40:00 -0800110
Benny Peake9190a132016-11-02 12:57:01 -0700111 def __init__(self, test_station, zip_file_path):
112 """
113 @param test_station: The teststation this package is on.
114 @param zip_file_path: The path to the zip file on the test station that
115 holds the package on the teststation.
116 """
117 self.test_station = test_station
118 self.zip_file = zip_file_path
119
120 def create_container(self,
121 container_directory,
122 internal_acts_directory=None):
123 """Unpacks this package into a container.
124
Benny Peake9519ea82016-12-02 17:23:38 -0800125 Unpacks this acts package into a container to interact with acts.
Benny Peake9190a132016-11-02 12:57:01 -0700126
127 @param container_directory: The directory on the teststation to hold
128 the container.
129 @param internal_acts_directory: The directory inside of the package
130 that holds acts.
131
132 @returns: An ActsContainer with info on the unpacked acts container.
133 """
Benny Peake9519ea82016-12-02 17:23:38 -0800134 self.test_station.run('unzip "%s" -x -d "%s"' %
135 (self.zip_file, container_directory))
136
Joe Brennana0db27c2017-02-27 15:40:00 -0800137 return ActsContainer(
138 self.test_station,
139 container_directory,
140 acts_directory=internal_acts_directory)
Benny Peake9519ea82016-12-02 17:23:38 -0800141
142 def create_enviroment(self,
143 container_directory,
144 testbed,
145 testbed_name=None,
146 internal_acts_directory=None):
147 """Unpacks this package into an acts testing enviroment.
148
149 Unpacks this acts package into a test enviroment to test with acts.
150
151 @param container_directory: The directory on the teststation to hold
152 the test enviroment.
153 @param testbed: The testbed that the test enviroment
154 will be testing on.
155 @param testbed_name: An overriding name for the testbed.
156 @param internal_acts_directory: The directory inside of the package
157 that holds acts.
158
159 @returns: An ActsTestingEnviroment with info on the unpacked
160 acts testing enviroment.
161 """
Benny Peake591cff42016-11-21 16:17:29 -0800162 if testbed.teststation != self.test_station:
163 raise error.TestError('Creating a contianer for a testbed on a '
Joe Brennana0db27c2017-02-27 15:40:00 -0800164 'different teststation is not allowed.')
Benny Peake591cff42016-11-21 16:17:29 -0800165
Benny Peake9190a132016-11-02 12:57:01 -0700166 self.test_station.run('unzip "%s" -x -d "%s"' %
167 (self.zip_file, container_directory))
168
Joe Brennana0db27c2017-02-27 15:40:00 -0800169 return ActsTestingEnviroment(
170 testbed=testbed,
171 container_directory=container_directory,
172 testbed_name=testbed_name,
173 acts_directory=internal_acts_directory)
Benny Peake9190a132016-11-02 12:57:01 -0700174
175
Benny Peake591cff42016-11-21 16:17:29 -0800176class AndroidTestingEnviroment(object):
177 """A container for testing android devices on a test station."""
Joe Brennana0db27c2017-02-27 15:40:00 -0800178
Benny Peake9519ea82016-12-02 17:23:38 -0800179 def __init__(self, testbed, testbed_name=None):
Benny Peake591cff42016-11-21 16:17:29 -0800180 """Creates a new android testing enviroment.
181
182 @param testbed: The testbed to test on.
Benny Peake591cff42016-11-21 16:17:29 -0800183 @param testbed_name: An overriding name for the testbed.
Benny Peake9190a132016-11-02 12:57:01 -0700184 """
Benny Peake591cff42016-11-21 16:17:29 -0800185 self.testbed = testbed
186
187 if not testbed_name:
188 # If no override is given get the name from the hostname.
189 hostname = testbed.hostname
190 if dnsname_mangler.is_ip_address(hostname):
191 testbed_name = hostname
192 else:
193 testbed_name = hostname.split('.')[0]
194
195 self.testbed_name = testbed_name
196
Benny Peake591cff42016-11-21 16:17:29 -0800197 def install_sl4a_apk(self):
Benny Peake2573fae2016-11-28 15:15:52 -0800198 """Install sl4a to a test bed."""
Benny Peake591cff42016-11-21 16:17:29 -0800199 for serial, adb_host in self.testbed.get_adb_devices().iteritems():
200 adb_utils.install_apk_from_build(
Joe Brennana0db27c2017-02-27 15:40:00 -0800201 adb_host,
202 constants.SL4A_APK,
203 constants.SL4A_ARTIFACT,
204 package_name=constants.SL4A_PACKAGE)
Benny Peake591cff42016-11-21 16:17:29 -0800205
206 def install_apk(self, apk_info):
207 """Installs an additional apk on all adb devices.
Benny Peake2573fae2016-11-28 15:15:52 -0800208
209 @param apk_info: A dictionary contianing the apk info. This dictionary
210 should contain the keys:
211 apk="Name of the apk",
212 package="Name of the package".
213 artifact="Name of the artifact", if missing
214 the package name is used."
Benny Peake591cff42016-11-21 16:17:29 -0800215 """
216 for serial, adb_host in self.testbed.get_adb_devices().iteritems():
217 adb_utils.install_apk_from_build(
Joe Brennana0db27c2017-02-27 15:40:00 -0800218 adb_host,
219 apk_info['apk'],
220 apk_info.get('artifact') or constants.SL4A_ARTIFACT,
221 package_name=apk_info['package'])
Benny Peake591cff42016-11-21 16:17:29 -0800222
223
Benny Peake9519ea82016-12-02 17:23:38 -0800224class ActsContainer(object):
225 """A container for working with acts."""
Joe Brennana0db27c2017-02-27 15:40:00 -0800226
227 def __init__(self, test_station, container_directory, acts_directory=None):
Benny Peake591cff42016-11-21 16:17:29 -0800228 """
Benny Peake9519ea82016-12-02 17:23:38 -0800229 @param test_station: The test station that the container is on.
Benny Peake9190a132016-11-02 12:57:01 -0700230 @param container_directory: The directory on the teststation this
231 container operates out of.
232 @param acts_directory: The directory within the container that holds
233 acts. If none then it defaults to
234 DEFAULT_ACTS_INTERNAL_DIRECTORY.
235 """
Benny Peake9519ea82016-12-02 17:23:38 -0800236 self.test_station = test_station
237 self.container_directory = container_directory
Benny Peake9190a132016-11-02 12:57:01 -0700238
239 if not acts_directory:
240 acts_directory = DEFAULT_ACTS_INTERNAL_DIRECTORY
241
242 if not os.path.isabs(acts_directory):
243 self.acts_directory = os.path.join(container_directory,
244 acts_directory)
245 else:
246 self.acts_directory = acts_directory
247
Benny Peake9190a132016-11-02 12:57:01 -0700248 self.tests_directory = os.path.join(self.acts_directory, TEST_DIR_NAME)
249 self.framework_directory = os.path.join(self.acts_directory,
250 FRAMEWORK_DIR_NAME)
Benny Peake9190a132016-11-02 12:57:01 -0700251
252 self.acts_file = os.path.join(self.framework_directory,
253 ACTS_EXECUTABLE_IN_FRAMEWORK)
254
255 self.setup_file = os.path.join(self.framework_directory,
256 SETUP_FILE_NAME)
257
Benny Peake9190a132016-11-02 12:57:01 -0700258 def get_test_paths(self):
259 """Get all test paths within this container.
260
261 Gets all paths that hold tests within the container.
262
263 @returns: A list of paths on the teststation that hold tests.
264 """
265 get_test_paths_result = self.test_station.run('find %s -type d' %
266 self.tests_directory)
267 test_search_dirs = get_test_paths_result.stdout.splitlines()
268 return test_search_dirs
269
270 def get_python_path(self):
271 """Get the python path being used.
272
273 Gets the python path that will be set in the enviroment for this
274 container.
275
276 @returns: A string of the PYTHONPATH enviroment variable to be used.
277 """
278 return '%s:$PYTHONPATH' % self.framework_directory
279
280 def get_enviroment(self):
281 """Gets the enviroment variables to be used for this container.
282
283 @returns: A dictionary of enviroment variables to be used by this
284 container.
285 """
Joe Brennana0db27c2017-02-27 15:40:00 -0800286 env = {
287 ACTS_TESTPATHS_ENV_KEY: ':'.join(self.get_test_paths()),
288 ACTS_LOGPATH_ENV_KEY: self.log_directory,
289 ACTS_PYTHONPATH_ENV_KEY: self.get_python_path()
290 }
Benny Peake9190a132016-11-02 12:57:01 -0700291
292 return env
293
294 def upload_file(self, src, dst):
295 """Uploads a file to be used by the container.
296
297 Uploads a file from the drone to the test staiton to be used by the
298 test container.
299
300 @param src: The source file on the drone. If a relative path is given
301 it is assumed to exist in CONFIG_FOLDER_LOCATION.
302 @param dst: The destination on the teststation. If a relative path is
303 given it is assumed that it is within the container.
304
305 @returns: The full path on the teststation.
306 """
307 if not os.path.isabs(src):
308 src = os.path.join(CONFIG_FOLDER_LOCATION, src)
309
310 if not os.path.isabs(dst):
311 dst = os.path.join(self.container_directory, dst)
312
Benny Peakef1b9f392016-11-30 18:25:38 -0800313 path = os.path.dirname(dst)
Joe Brennana0db27c2017-02-27 15:40:00 -0800314 result = self.test_station.run('mkdir "%s"' % path, ignore_status=True)
Benny Peakef1b9f392016-11-30 18:25:38 -0800315
316 original_dst = dst
317 if os.path.basename(src) == os.path.basename(dst):
318 dst = os.path.dirname(dst)
Benny Peake9190a132016-11-02 12:57:01 -0700319
320 self.test_station.send_file(src, dst)
321
Benny Peakef1b9f392016-11-30 18:25:38 -0800322 return original_dst
Benny Peake9190a132016-11-02 12:57:01 -0700323
Benny Peake9519ea82016-12-02 17:23:38 -0800324 def setup_enviroment(self, python_bin='python'):
325 """Sets up the teststation system enviroment so the container can run.
326
327 Prepares the remote system so that the container can run. This involves
328 uninstalling all versions of acts for the version of python being
329 used and installing all needed dependencies.
330
331 @param python_bin: The python binary to use.
332 """
333 uninstall_command = '%s %s uninstall' % (python_bin, self.setup_file)
334 install_deps_command = '%s %s install_deps' % (python_bin,
335 self.setup_file)
336
337 self.test_station.run(uninstall_command)
338 self.test_station.run(install_deps_command)
339
340
341class ActsTestingEnviroment(ActsContainer, AndroidTestingEnviroment):
342 """A container for running acts tests with a contained version of acts."""
Joe Brennana0db27c2017-02-27 15:40:00 -0800343
Benny Peake9519ea82016-12-02 17:23:38 -0800344 def __init__(self,
345 container_directory,
346 testbed,
347 testbed_name=None,
348 acts_directory=None):
349 """
350 @param testbed: The testbed to test on.
351 @param container_directory: The directory on the teststation this
352 container operates out of.
353 @param testbed_name: An overriding name for the testbed.
354 @param acts_directory: The directory within the container that holds
355 acts. If none then it defaults to
356 DEFAULT_ACTS_INTERNAL_DIRECTORY.
357 """
Joe Brennana0db27c2017-02-27 15:40:00 -0800358 AndroidTestingEnviroment.__init__(
359 self, testbed, testbed_name=testbed_name)
Benny Peake9519ea82016-12-02 17:23:38 -0800360
Joe Brennana0db27c2017-02-27 15:40:00 -0800361 ActsContainer.__init__(
362 self,
363 testbed.teststation,
364 container_directory=container_directory,
365 acts_directory=acts_directory)
Benny Peake9519ea82016-12-02 17:23:38 -0800366
367 self.config_location = os.path.join(self.container_directory,
368 CONFIG_DIR_NAME)
369
370 self.log_directory = os.path.join(self.container_directory,
371 LOG_DIR_NAME)
372
373 self.acts_file = os.path.join(self.framework_directory,
374 ACTS_EXECUTABLE_IN_FRAMEWORK)
375
376 self.working_directory = os.path.join(container_directory,
377 CONFIG_DIR_NAME)
378 self.test_station.run('mkdir %s' % self.working_directory,
Joe Brennana0db27c2017-02-27 15:40:00 -0800379 ignore_status=True)
Benny Peake9519ea82016-12-02 17:23:38 -0800380
381 self.configs = {}
382 self.campaigns = {}
383
Benny Peake9190a132016-11-02 12:57:01 -0700384 def upload_config(self, config_file):
385 """Uploads a config file to the container.
386
387 Uploads a config file to the config folder in the container.
388
389 @param config_file: The config file to upload. This must be a file
390 within the autotest_config directory under the
391 CONFIG_FOLDER_LOCATION.
392
393 @returns: The full path of the config on the test staiton.
394 """
395 full_name = os.path.join(CONFIG_DIR_NAME, config_file)
396
397 full_path = self.upload_file(full_name, full_name)
398 self.configs[config_file] = full_path
399
400 return full_path
401
402 def upload_campaign(self, campaign_file):
403 """Uploads a campaign file to the container.
404
405 Uploads a campaign file to the campaign folder in the container.
406
407 @param campaign_file: The campaign file to upload. This must be a file
408 within the autotest_campaign directory under the
409 CONFIG_FOLDER_LOCATION.
410
411 @returns: The full path of the campaign on the test staiton.
412 """
413 full_name = os.path.join(CAMPAIGN_DIR_NAME, campaign_file)
414
415 full_path = self.upload_file(full_name, full_name)
416 self.campaigns[campaign_file] = full_path
417
418 return full_path
419
Benny Peake9190a132016-11-02 12:57:01 -0700420 def run_test(self,
Benny Peake9190a132016-11-02 12:57:01 -0700421 config,
422 campaign=None,
423 test_case=None,
424 extra_env={},
425 python_bin='python',
Joe Brennana0db27c2017-02-27 15:40:00 -0800426 timeout=7200,
427 additional_cmd_line_params=None):
Benny Peake9190a132016-11-02 12:57:01 -0700428 """Runs a test within the container.
429
430 Runs a test within a container using the given settings.
431
Benny Peake9190a132016-11-02 12:57:01 -0700432 @param config: The name of the config file to use as the main config.
433 This should have already been uploaded with
434 upload_config. The string passed into upload_config
435 should be used here.
436 @param campaign: The campaign file to use for this test. If none then
437 test_case is assumed. This file should have already
438 been uploaded with upload_campaign. The string passed
439 into upload_campaign should be used here.
440 @param test_case: The test case to run the test with. If none then the
Benny Peake913791f2016-12-08 11:00:56 -0800441 campaign will be used. If multiple are given,
442 multiple will be run.
Benny Peake9190a132016-11-02 12:57:01 -0700443 @param extra_env: Extra enviroment variables to run the test with.
444 @param python_bin: The python binary to execute the test with.
Benny Peake9190a132016-11-02 12:57:01 -0700445 @param timeout: How many seconds to wait before timing out.
Joe Brennana0db27c2017-02-27 15:40:00 -0800446 @param additional_cmd_line_params: Adds the ability to add any string
447 to the end of the acts.py command
448 line string. This is intended to
449 add acts command line flags however
450 this is unbounded so it could cause
451 errors if incorrectly set.
Benny Peake9190a132016-11-02 12:57:01 -0700452
453 @returns: The results of the test run.
454 """
Benny Peake9190a132016-11-02 12:57:01 -0700455 if not config in self.configs:
456 # Check if the config has been uploaded and upload if it hasn't
457 self.upload_config(config)
458
459 full_config = self.configs[config]
460
461 if campaign:
462 # When given a campaign check if it's upload.
463 if not campaign in self.campaigns:
464 self.upload_campaign(campaign)
465
466 full_campaign = self.campaigns[campaign]
467 else:
468 full_campaign = None
469
470 full_env = self.get_enviroment()
471
472 # Setup enviroment variables.
473 if extra_env:
474 for k, v in extra_env.items():
475 full_env[k] = extra_env
476
477 logging.info('Using env: %s', full_env)
478 exports = ('export %s=%s' % (k, v) for k, v in full_env.items())
479 env_command = ';'.join(exports)
480
481 # Make sure to execute in the working directory.
482 command_setup = 'cd %s' % self.working_directory
483
Joe Brennana0db27c2017-02-27 15:40:00 -0800484 if additional_cmd_line_params:
485 act_base_cmd = '%s %s -c %s -tb %s %s ' % (
486 python_bin, self.acts_file, full_config, self.testbed_name,
487 additional_cmd_line_params)
488 else:
489 act_base_cmd = '%s %s -c %s -tb %s ' % (
490 python_bin, self.acts_file, full_config, self.testbed_name)
Benny Peake9190a132016-11-02 12:57:01 -0700491
492 # Format the acts command based on what type of test is being run.
493 if test_case and campaign:
494 raise error.TestError(
Joe Brennana0db27c2017-02-27 15:40:00 -0800495 'campaign and test_file cannot both have a value.')
Benny Peake9190a132016-11-02 12:57:01 -0700496 elif test_case:
Benny Peake913791f2016-12-08 11:00:56 -0800497 if isinstance(test_case, str):
498 test_case = [test_case]
499 if len(test_case) < 1:
500 raise error.TestError('At least one test case must be given.')
501
502 tc_str = ''
503 for tc in test_case:
504 tc_str = '%s %s' % (tc_str, tc)
505 tc_str = tc_str.strip()
506
507 act_cmd = '%s -tc %s' % (act_base_cmd, tc_str)
Benny Peake9190a132016-11-02 12:57:01 -0700508 elif campaign:
509 act_cmd = '%s -tf %s' % (act_base_cmd, full_campaign)
510 else:
511 raise error.TestFail('No tests was specified!')
512
513 # Format all commands into a single command.
514 command_list = [command_setup, env_command, act_cmd]
515 full_command = '; '.join(command_list)
516
517 try:
518 # Run acts on the remote machine.
519 act_result = self.test_station.run(full_command, timeout=timeout)
520 excep = None
521 except Exception as e:
522 # Catch any error to store in the results.
523 act_result = None
524 excep = e
525
Joe Brennana0db27c2017-02-27 15:40:00 -0800526 return ActsTestResults(
527 str(test_case) or campaign,
528 self.testbed,
529 testbed_name=self.testbed_name,
530 run_result=act_result,
531 log_directory=self.log_directory,
532 exception=excep)
Benny Peake9190a132016-11-02 12:57:01 -0700533
534
535class ActsTestResults(object):
536 """The packaged results of a test run."""
537 acts_result_to_autotest = {
538 'PASS': 'GOOD',
539 'FAIL': 'FAIL',
540 'UNKNOWN': 'WARN',
541 'SKIP': 'ABORT'
542 }
543
544 def __init__(self,
545 name,
546 testbed,
547 testbed_name=None,
548 run_result=None,
Benny Peake51c675b2016-11-15 15:55:39 -0800549 log_directory=None,
Benny Peake9190a132016-11-02 12:57:01 -0700550 exception=None):
551 """
552 @param name: A name to identify the test run.
553 @param testbed: The testbed that ran the test.
554 @param testbed_name: The name the testbed was run with, if none the
555 default name of the testbed is used.
556 @param run_result: The raw i/o result of the test run.
Benny Peake51c675b2016-11-15 15:55:39 -0800557 @param log_directory: The directory that acts logged to.
Benny Peake9190a132016-11-02 12:57:01 -0700558 @param exception: An exception that was thrown while running the test.
559 """
560 self.name = name
561 self.run_result = run_result
Benny Peake9190a132016-11-02 12:57:01 -0700562 self.exception = exception
Benny Peake51c675b2016-11-15 15:55:39 -0800563 self.log_directory = log_directory
564 self.test_station = testbed.teststation
Benny Peake9190a132016-11-02 12:57:01 -0700565
566 self.testbed = testbed
567 if not testbed_name:
568 # If no override is given get the name from the hostname.
569 hostname = testbed.hostname
570 if dnsname_mangler.is_ip_address(hostname):
571 self.testbed_name = hostname
572 else:
573 self.testbed_name = hostname.split('.')[0]
574 else:
575 self.testbed_name = testbed_name
576
577 self.reported_to = set()
578
Benny Peake51c675b2016-11-15 15:55:39 -0800579 self.json_results = {}
580 self.results_dir = None
581 if self.log_directory:
582 self.results_dir = os.path.join(self.log_directory,
583 self.testbed_name, 'latest')
584 results_file = os.path.join(self.results_dir,
585 'test_run_summary.json')
586 cat_log_result = self.test_station.run('cat %s' % results_file,
587 ignore_status=True)
588 if not cat_log_result.exit_status:
589 self.json_results = json.loads(cat_log_result.stdout)
590
Benny Peake9190a132016-11-02 12:57:01 -0700591 def log_output(self):
592 """Logs the output of the test."""
593 if self.run_result:
594 logging.debug('ACTS Output:\n%s', self.run_result.stdout)
595
596 def rethrow_exception(self):
597 """Re-throws the exception thrown during the test."""
598 if self.exception:
599 raise self.exception
600
Benny Peake51c675b2016-11-15 15:55:39 -0800601 def upload_to_local(self, local_dir):
602 """Saves all acts results to a local directory.
Benny Peake9190a132016-11-02 12:57:01 -0700603
Benny Peake51c675b2016-11-15 15:55:39 -0800604 @param local_dir: The directory on the local machine to save all results
605 to.
Benny Peake9190a132016-11-02 12:57:01 -0700606 """
Benny Peake51c675b2016-11-15 15:55:39 -0800607 if self.results_dir:
608 self.test_station.get_file(self.results_dir, local_dir)
Benny Peake9190a132016-11-02 12:57:01 -0700609
610 def upload_to_sponge(self, test):
611 """Uploads the results to sponge.
612
613 @param test: The autotest test object to upload.
614 """
Benny Peake51c675b2016-11-15 15:55:39 -0800615 if self.results_dir:
616 self.report_to_autotest(test)
617 summary_file = os.path.join(test.resultsdir,
618 'test_run_summary.json')
Joe Brennana0db27c2017-02-27 15:40:00 -0800619 sponge_utils.upload_results_in_test(
620 test, acts_summary=summary_file)
Benny Peake9190a132016-11-02 12:57:01 -0700621
622 def report_to_autotest(self, test):
623 """Reports the results to an autotest test object.
624
Benny Peake51c675b2016-11-15 15:55:39 -0800625 Reports the results to the test and saves all acts results under the
626 tests results directory.
627
Benny Peake9190a132016-11-02 12:57:01 -0700628 @param test: The autotest test object to report to. If this test object
629 has already recived our report then this call will be
630 ignored.
631 """
632 if test in self.reported_to:
633 return
634
Benny Peake51c675b2016-11-15 15:55:39 -0800635 if self.results_dir:
636 self.upload_to_local(test.resultsdir)
637
Benny Peake9190a132016-11-02 12:57:01 -0700638 if not 'Results' in self.json_results:
639 return
640
641 results = self.json_results['Results']
642 for result in results:
643 verdict = self.acts_result_to_autotest[result['Result']]
644 details = result['Details']
645 test.job.record(verdict, None, self.name, status=(details or ''))
646
647 self.reported_to.add(test)