blob: 6ed55308311b9e870fdff712369d1f6c4593dd7b [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Exposes the builder and recipe configurations to GenTests in recipes.
import re
from recipe_engine import recipe_test_api
from . import builders
from . import testing
# Simulated branch names for testing. Optionally upgrade these in branch
# period to reflect the real branches used by the gitiles poller.
STABLE_BRANCH = '4.2'
BETA_BRANCH = '4.3'
def _sanitize_nonalpha(text):
return ''.join(c if c.isalnum() else '_' for c in text)
class V8TestApi(recipe_test_api.RecipeTestApi):
BUILDERS = builders.BUILDERS
SLOWEST_TESTS = [
{
'name': 'mjsunit/Cool.Test',
'flags': ['-f'],
'command': 'd8 -f mjsunit/Cool.Test',
'duration': 61.0028,
},
{
'name': 'mjsunit/Cool.Test2',
'flags': ['-f', '-g'],
'command': 'd8 -f mjsunit/Cool.Test2',
'duration': 0.1012,
},
]
def iter_builders(self):
return builders.iter_builders()
def output_json(self, has_failures=False, wrong_results=False, flakes=False,
unmarked_slow_test=False):
slowest_tests = V8TestApi.SLOWEST_TESTS
if unmarked_slow_test:
slowest_tests += [{
'name': 'mjsunit/slow',
'flags': [],
'command': 'd8 -f mjsunit/slow',
'duration': 123.0,
'marked_slow': False,
}]
if not has_failures:
return self.m.json.output([{
'arch': 'theArch',
'mode': 'theMode',
'results': [],
'slowest_tests': slowest_tests,
}])
if wrong_results:
return self.m.json.output([{
'arch': 'theArch1',
'mode': 'theMode1',
'results': [],
'slowest_tests': slowest_tests,
},
{
'arch': 'theArch2',
'mode': 'theMode2',
'results': [],
'slowest_tests': slowest_tests,
}])
if flakes:
return self.m.json.output([{
'arch': 'theArch1',
'mode': 'theMode1',
'results': [
{
'flags': [],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 3,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/test-name',
'command': 'd8 test.js',
'exit_code': 1,
},
{
'flags': [],
'result': 'PASS',
'expected': ['PASS', 'SLOW'],
'duration': 10,
'variant': 'default',
'random_seed': 123,
'run': 2,
'stdout': 'Some output.',
'stderr': '',
'name': 'suite-name/dir/test-name',
'command': 'd8 test.js',
'exit_code': 1,
},
{
'flags': [],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 1.5,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/test-name2',
'command': 'd8 test.js',
'exit_code': 1,
},
{
'flags': [],
'result': 'PASS',
'expected': ['PASS', 'SLOW'],
'duration': 10,
'variant': 'default',
'random_seed': 123,
'run': 2,
'stdout': 'Some output.',
'stderr': '',
'name': 'suite-name/dir/test-name2',
'command': 'd8 test.js',
'exit_code': 1,
},
],
'slowest_tests': slowest_tests,
}])
# Add enough failures to exceed the maximum number of shown failures
# (test-name9 will be cut off).
results = []
for i in range(0, 10):
results.append({
'flags': ['--opt42'],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 61.0028,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/test-name%d' % i,
'command': 'out/theMode/d8 --opt42 test/suite-name/dir/test-name.js',
'exit_code': 1,
})
results.append({
'flags': ['--other'],
'result': 'FAIL',
'duration': 3599.9999,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/test-name%d' % i,
'command': 'out/theMode/d8 --other test/suite-name/dir/test-name.js',
'exit_code': 1,
})
results.append({
'flags': ['--other'],
'result': 'CRASH',
'duration': 0.1111,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output\nwith\nmore\nlines.',
'stderr': 'Some errput.',
'name': 'other-suite/dir/other-test-very-long-name%d' % i,
'command': ('out/theMode/d8 --other '
'test/other-suite/dir/other-test-very-long-name.js'),
'exit_code': 1,
})
return self.m.json.output([{
'arch': 'theArch',
'mode': 'theMode',
'results': results,
'slowest_tests': slowest_tests,
}])
def one_failure(self):
return self.m.json.output([{
'arch': 'theArch',
'mode': 'theMode',
'results': [
{
'flags': [],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 5,
'variant': 'default',
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/test-name',
'command': 'd8 test.js',
'target_name': 'd8',
'exit_code': 1,
},
],
'slowest_tests': V8TestApi.SLOWEST_TESTS,
}])
def failures_example(self, variant='default'):
return self.m.json.output([{
'arch': 'theArch',
'mode': 'theMode',
'results': [
{
'flags': [],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 3,
'variant': variant,
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/slow',
'command': 'd8 test.js',
'target_name': 'd8',
'exit_code': 1,
},
{
'flags': [],
'result': 'FAIL',
'expected': ['PASS', 'SLOW'],
'duration': 1.5,
'variant': variant,
'random_seed': 123,
'run': 1,
'stdout': 'Some output.',
'stderr': 'Some errput.',
'name': 'suite-name/dir/fast',
'command': 'd8 test.js',
'target_name': 'd8',
'exit_code': 1,
},
],
'slowest_tests': V8TestApi.SLOWEST_TESTS,
}])
def example_buildbot_changes(self):
return self.m.json.output({
'changes': [
{'revision': 'a1'},
{'revision': 'a2'},
{'revision': 'a3'},
]
})
def example_one_buildbot_change(self):
return self.m.json.output({
'changes': [
{'revision': 'a1'},
]
})
def example_bisection_range(self):
# Gitiles returns changes in the order newest -> oldest.
return self.m.json.output({
'log': [
{'commit': 'a3', 'msg': 'Cool commit 3'},
{'commit': 'a2', 'msg': 'Cool commit 2'},
{'commit': 'a1', 'msg': 'Cool commit 1'},
{'commit': 'a0', 'msg': 'Cool commit 0'},
],
})
def example_bisection_range_one_change(self):
# A1 is the single change in the range, while a0 is the latest previous
# before the range.
return self.m.json.output({
'log': [
{'commit': 'a1', 'msg': 'Cool commit 1'},
{'commit': 'a0', 'msg': 'Cool commit 0'},
],
})
def example_available_builds(self, revision):
# When 'gsutil ls' is called, it will only find builds for a1 or a3.
available_builds = {
'a1': 'gs://chromium-v8/v8-linux64-dbg/full-build-linux_a1.zip',
'a3': 'gs://chromium-v8/v8-linux64-dbg/full-build-linux_a3.zip',
}
return self.m.raw_io.stream_output(
available_builds.get(revision, ''),
stream='stdout',
)
def _get_test_branch_name(self, mastername, buildername):
if mastername == 'client.dart.fyi':
return STABLE_BRANCH
if re.search(r'stable branch', buildername):
return STABLE_BRANCH
if re.search(r'beta branch', buildername):
return BETA_BRANCH
return 'master'
def _make_dummy_swarm_hashes(self, bot_config):
"""Makes dummy isolate hashes for all tests of a bot.
Either an explicit isolate target must be defined or the naming
convention "test name == isolate target name" will be used.
"""
def gen_isolate_targets(test_config):
config = testing.TEST_CONFIGS.get(test_config.name, {})
if config.get('isolated_target'):
yield config['isolated_target']
else:
for test in config.get('tests', []):
yield test
return dict(
(target, '[dummy hash for %s]' % target)
for test_config in bot_config.get('tests', [])
for target in gen_isolate_targets(test_config)
)
def test(self, mastername, buildername, suffix='', **kwargs):
name = '_'.join(filter(bool, [
'full',
_sanitize_nonalpha(mastername),
_sanitize_nonalpha(buildername),
suffix,
]))
builders_list = builders.BUILDERS[mastername]['builders']
bot_config = builders_list[buildername]
v8_config_kwargs = bot_config.get('v8_config_kwargs', {})
parent_buildername = bot_config.get('parent_buildername')
branch=self._get_test_branch_name(mastername, buildername)
if bot_config.get('bot_type') in ['builder', 'builder_tester']:
assert parent_buildername is None
if mastername.startswith('tryserver'):
properties_fn = self.m.properties.tryserver
else:
properties_fn = self.m.properties.generic
test = (
recipe_test_api.RecipeTestApi.test(name) +
properties_fn(
mastername=mastername,
buildername=buildername,
branch=branch,
parent_buildername=parent_buildername,
revision='20123',
**kwargs
) +
self.m.platform(
bot_config['testing']['platform'],
v8_config_kwargs.get('TARGET_BITS', 64),
)
)
if parent_buildername:
test += self.m.properties(
parent_got_revision='54321',
parent_build_environment={
'useful': 'envvars', 'from': 'the', 'parent': 'bot'},
)
if bot_config.get('enable_swarming'):
# Assume each tester is triggered with the required hashes for all
# tests.
test += self.m.properties(
parent_got_swarming_client_revision='[dummy swarming client hash]',
swarm_hashes=self._make_dummy_swarm_hashes(bot_config),
)
if mastername.startswith('tryserver'):
test += self.m.properties(
category='cq',
master='tryserver.v8',
patch_project='v8',
patch_storage='rietveld',
reason='CQ',
revision='12345',
try_job_key='1234',
)
return test
def fail(self, step_name, variant='default'):
return self.override_step_data(
step_name, self.failures_example(variant=variant))