#!/usr/bin/env python # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. import copy import os import sys # load modules from parent dir sys.path.insert(1, os.path.dirname(sys.path[0])) from mozharness.base.python import PreScriptAction from mozharness.base.python import ( VirtualenvMixin, virtualenv_config_options, ) from mozharness.base.script import BaseScript from mozharness.mozilla.buildbot import ( BuildbotMixin, TBPL_SUCCESS, TBPL_WARNING, TBPL_FAILURE, TBPL_EXCEPTION ) marionette_harness_tests_config_options = [ [['--tests'], { 'dest': 'test_path', 'default': None, 'help': 'Path to test_*.py or directory relative to src root.', }], [['--src-dir'], { 'dest': 'rel_src_dir', 'default': None, 'help': 'Path to hg.mo source checkout relative to work dir.', }], ] + copy.deepcopy(virtualenv_config_options) marionette_harness_tests_config = { "find_links": [ "http://pypi.pub.build.mozilla.org/pub", ], "pip_index": False, # relative to workspace "rel_src_dir": os.path.join("build", "src"), } class MarionetteHarnessTests(VirtualenvMixin, BuildbotMixin, BaseScript): def __init__(self, config_options=None, all_actions=None, default_actions=None, *args, **kwargs): config_options = config_options or marionette_harness_tests_config_options actions = [ 'clobber', 'create-virtualenv', 'run-tests', ] super(MarionetteHarnessTests, self).__init__( config_options=config_options, all_actions=all_actions or actions, default_actions=default_actions or actions, config=marionette_harness_tests_config, *args, **kwargs) @PreScriptAction('create-virtualenv') def _pre_create_virtualenv(self, action): dirs = self.query_abs_dirs() c = self.config requirements = os.path.join( dirs['abs_src_dir'], 'testing', 'config', 'marionette_harness_test_requirements.txt' ) self.register_virtualenv_module( requirements=[requirements], two_pass=True ) def query_abs_dirs(self): if self.abs_dirs: return self.abs_dirs c = self.config abs_dirs = super(MarionetteHarnessTests, self).query_abs_dirs() dirs = { 'abs_src_dir': os.path.abspath( os.path.join(abs_dirs['base_work_dir'], c['rel_src_dir']) ), } for key in dirs: if key not in abs_dirs: abs_dirs[key] = dirs[key] self.abs_dirs = abs_dirs return self.abs_dirs def _get_pytest_status(self, code): """ Translate pytest exit code to TH status Based on https://github.com/pytest-dev/pytest/blob/master/_pytest/main.py#L21-L26 """ if code == 0: return TBPL_SUCCESS elif code == 1: return TBPL_WARNING elif 1 < code < 6: self.error("pytest returned exit code: %s" % code) return TBPL_FAILURE else: return TBPL_EXCEPTION def run_tests(self): """Run all the tests""" dirs = self.query_abs_dirs() test_relpath = self.config.get( 'test_path', os.path.join('testing', 'marionette', 'harness', 'marionette_harness', 'tests', 'harness_unit') ) test_path = os.path.join(dirs['abs_src_dir'], test_relpath) self.activate_virtualenv() import pytest command = ['-p', 'no:terminalreporter', # disable pytest logging test_path] logs = {} for fmt in ['tbpl', 'mach', 'raw']: logs[fmt] = os.path.join(dirs['abs_log_dir'], 'mn-harness_{}.log'.format(fmt)) command.extend(['--log-'+fmt, logs[fmt]]) self.info('Calling pytest.main with the following arguments: %s' % command) status = self._get_pytest_status(pytest.main(command)) self.read_from_file(logs['tbpl']) for log in logs.values(): self.copy_to_upload_dir(log, dest='logs/') self.buildbot_status(status) if __name__ == '__main__': script = MarionetteHarnessTests() script.run_and_exit()