1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import, print_function, unicode_literals 6 7import copy 8import logging 9 10from . import transform 11from ..util.yaml import load_yaml 12 13logger = logging.getLogger(__name__) 14 15 16class TestTask(transform.TransformTask): 17 """ 18 A task implementing a Gecko test. 19 """ 20 21 @classmethod 22 def get_inputs(cls, kind, path, config, params, loaded_tasks): 23 24 # the kind on which this one depends 25 if len(config.get('kind-dependencies', [])) != 1: 26 raise Exception("TestTask kinds must have exactly one item in kind-dependencies") 27 dep_kind = config['kind-dependencies'][0] 28 29 # get build tasks, keyed by build platform 30 builds_by_platform = cls.get_builds_by_platform(dep_kind, loaded_tasks) 31 32 # get the test platforms for those build tasks 33 test_platforms_cfg = load_yaml(path, 'test-platforms.yml') 34 test_platforms = cls.get_test_platforms(test_platforms_cfg, builds_by_platform) 35 36 # expand the test sets for each of those platforms 37 test_sets_cfg = load_yaml(path, 'test-sets.yml') 38 test_platforms = cls.expand_tests(test_sets_cfg, test_platforms) 39 40 # load the test descriptions 41 test_descriptions = load_yaml(path, 'tests.yml') 42 43 # generate all tests for all test platforms 44 for test_platform_name, test_platform in test_platforms.iteritems(): 45 for test_name in test_platform['test-names']: 46 test = copy.deepcopy(test_descriptions[test_name]) 47 test['build-platform'] = test_platform['build-platform'] 48 test['test-platform'] = test_platform_name 49 test['build-label'] = test_platform['build-label'] 50 test['test-name'] = test_name 51 52 logger.debug("Generating tasks for {} test {} on platform {}".format( 53 kind, test_name, test['test-platform'])) 54 yield test 55 56 @classmethod 57 def get_builds_by_platform(cls, dep_kind, loaded_tasks): 58 """Find the build tasks on which tests will depend, keyed by 59 platform/type. Returns a dictionary mapping build platform to task 60 label.""" 61 builds_by_platform = {} 62 for task in loaded_tasks: 63 if task.kind != dep_kind: 64 continue 65 66 build_platform = task.attributes.get('build_platform') 67 build_type = task.attributes.get('build_type') 68 if not build_platform or not build_type: 69 continue 70 platform = "{}/{}".format(build_platform, build_type) 71 if platform in builds_by_platform: 72 raise Exception("multiple build jobs for " + platform) 73 builds_by_platform[platform] = task.label 74 return builds_by_platform 75 76 @classmethod 77 def get_test_platforms(cls, test_platforms_cfg, builds_by_platform): 78 """Get the test platforms for which test tasks should be generated, 79 based on the available build platforms. Returns a dictionary mapping 80 test platform to {test-set, build-platform, build-label}.""" 81 test_platforms = {} 82 for test_platform, cfg in test_platforms_cfg.iteritems(): 83 build_platform = cfg['build-platform'] 84 if build_platform not in builds_by_platform: 85 logger.warning( 86 "No build task with platform {}; ignoring test platform {}".format( 87 build_platform, test_platform)) 88 continue 89 test_platforms[test_platform] = { 90 'test-set': cfg['test-set'], 91 'build-platform': build_platform, 92 'build-label': builds_by_platform[build_platform], 93 } 94 return test_platforms 95 96 @classmethod 97 def expand_tests(cls, test_sets_cfg, test_platforms): 98 """Expand the test sets in `test_platforms` out to sets of test names. 99 Returns a dictionary like `get_test_platforms`, with an additional 100 `test-names` key for each test platform, containing a set of test 101 names.""" 102 rv = {} 103 for test_platform, cfg in test_platforms.iteritems(): 104 test_set = cfg['test-set'] 105 if test_set not in test_sets_cfg: 106 raise Exception( 107 "Test set '{}' for test platform {} is not defined".format( 108 test_set, test_platform)) 109 test_names = test_sets_cfg[test_set] 110 rv[test_platform] = cfg.copy() 111 rv[test_platform]['test-names'] = test_names 112 return rv 113