blob: 7513f2f842680a3e24aa90e33a6abf3965d74cd2 [file] [log] [blame]
# Copyright 2016 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.
import os
import string
import sys
import tempfile
import unittest
import json
import mock
from telemetry import project_config
from telemetry.core import util
from telemetry.testing import browser_test_runner
from telemetry.testing import serially_executed_browser_test_case
class BrowserTestRunnerTest(unittest.TestCase):
def baseTest(self, mockInitDependencyManager, test_filter,
failures, successes, test_name='SimpleTest'):
options = browser_test_runner.TestRunOptions()
options.verbosity = 0
config = project_config.ProjectConfig(
top_level_dir=os.path.join(util.GetTelemetryDir(), 'examples'),
client_configs=['a', 'b', 'c'],
benchmark_dirs=[
os.path.join(util.GetTelemetryDir(), 'examples', 'browser_tests')]
)
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.close()
temp_file_name = temp_file.name
try:
browser_test_runner.Run(
config, options,
[test_name,
'--write-abbreviated-json-results-to=%s' % temp_file_name,
'--test-filter=%s' % test_filter])
mockInitDependencyManager.assert_called_with(['a', 'b', 'c'])
with open(temp_file_name) as f:
test_result = json.load(f)
self.assertEquals(test_result['failures'], failures)
self.assertEquals(test_result['successes'], successes)
self.assertEquals(test_result['valid'], True)
finally:
os.remove(temp_file_name)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testJsonOutputFormatNegativeFilter(self, mockInitDependencyManager):
self.baseTest(
mockInitDependencyManager, '^(add|multiplier).*',
['add_1_and_2',
'add_7_and_3',
'multiplier_simple_2'],
['add_2_and_3',
'multiplier_simple',
'multiplier_simple_3'])
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testJsonOutputWhenSetupClassFailed(self, mockInitDependencyManager):
self.baseTest(
mockInitDependencyManager, '.*',
['setUpClass (browser_tests.failed_tests.SetUpClassFailedTest)'],
[], test_name='SetUpClassFailedTest')
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testJsonOutputWhenTearDownClassFailed(self, mockInitDependencyManager):
self.baseTest(
mockInitDependencyManager, '.*',
['tearDownClass (browser_tests.failed_tests.TearDownClassFailedTest)'],
sorted(['dummy_test_%i' %i for i in xrange(0, 100)]),
test_name='TearDownClassFailedTest')
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testJsonOutputFormatPositiveFilter(self, mockInitDependencyManager):
self.baseTest(
mockInitDependencyManager, '(TestSimple|TestException).*',
['TestException', 'TestSimple'], [])
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testExecutingTestsInSortedOrder(self, mockInitDependencyManager):
alphabetical_tests = []
prefix = 'Alphabetical_'
for i in xrange(20):
alphabetical_tests.append(prefix + str(i))
for c in string.uppercase[:26]:
alphabetical_tests.append(prefix + c)
for c in string.lowercase[:26]:
alphabetical_tests.append(prefix + c)
alphabetical_tests.sort()
self.baseTest(
mockInitDependencyManager, 'Alphabetical', [], alphabetical_tests)
def shardingRangeTestHelper(self, total_shards, num_tests):
shard_ranges = []
for shard_index in xrange(0, total_shards):
shard_ranges.append(browser_test_runner._TestRangeForShard(
total_shards, shard_index, num_tests))
# Make assertions about ranges
num_tests_run = 0
for i in xrange(0, len(shard_ranges)):
cur_range = shard_ranges[i]
if i < num_tests:
self.assertGreater(cur_range[1], cur_range[0])
num_tests_run += (cur_range[1] - cur_range[0])
else:
# Not enough tests to go around all of the shards.
self.assertEquals(cur_range[0], cur_range[1])
# Make assertions about non-overlapping ranges
for i in xrange(1, len(shard_ranges)):
prev_range = shard_ranges[i - 1]
cur_range = shard_ranges[i]
self.assertEquals(prev_range[1], cur_range[0])
# Assert that we run all of the tests (very important)
self.assertEquals(num_tests_run, num_tests)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testShardsWithPrimeNumTests(self, _):
for total_shards in xrange(1, 20):
# Nice non-prime number
self.shardingRangeTestHelper(total_shards, 101)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testShardsWithDivisibleNumTests(self, _):
for total_shards in xrange(1, 6):
self.shardingRangeTestHelper(total_shards, 8)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testShardBoundaryConditions(self, _):
self.shardingRangeTestHelper(1, 0)
self.shardingRangeTestHelper(1, 1)
self.shardingRangeTestHelper(2, 1)
def baseShardingTest(self, total_shards, shard_index, failures, successes,
opt_abbr_input_json_file=None,
opt_test_filter='',
opt_filter_tests_after_sharding=False):
options = browser_test_runner.TestRunOptions()
options.verbosity = 0
config = project_config.ProjectConfig(
top_level_dir=os.path.join(util.GetTelemetryDir(), 'examples'),
client_configs=['a', 'b', 'c'],
benchmark_dirs=[
os.path.join(util.GetTelemetryDir(), 'examples', 'browser_tests')]
)
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.close()
temp_file_name = temp_file.name
opt_args = []
if opt_abbr_input_json_file:
opt_args += [
'--read-abbreviated-json-results-from=%s' % opt_abbr_input_json_file]
if opt_test_filter:
opt_args += [
'--test-filter=%s' % opt_test_filter]
if opt_filter_tests_after_sharding:
opt_args += ['--filter-tests-after-sharding']
try:
browser_test_runner.Run(
config, options,
['SimpleShardingTest',
'--write-abbreviated-json-results-to=%s' % temp_file_name,
'--total-shards=%d' % total_shards,
'--shard-index=%d' % shard_index] + opt_args)
with open(temp_file_name) as f:
test_result = json.load(f)
self.assertEquals(test_result['failures'], failures)
self.assertEquals(test_result['successes'], successes)
self.assertEquals(test_result['valid'], True)
finally:
os.remove(temp_file_name)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testShardedTestRun(self, _):
self.baseShardingTest(3, 0, [], [
'Test1',
'Test2',
'Test3',
'passing_test_0',
'passing_test_1',
])
self.baseShardingTest(3, 1, [], [
'passing_test_2',
'passing_test_3',
'passing_test_4',
'passing_test_5',
])
self.baseShardingTest(3, 2, [], [
'passing_test_6',
'passing_test_7',
'passing_test_8',
'passing_test_9',
])
def writeMockTestResultsFile(self):
mock_test_results = {
'passes': [
'Test1',
'Test2',
'Test3',
'passing_test_0',
'passing_test_1',
'passing_test_2',
'passing_test_3',
'passing_test_4',
'passing_test_5',
'passing_test_6',
'passing_test_7',
'passing_test_8',
'passing_test_9',
],
'failures': [],
'valid': True,
'times': {
'Test1': 3.0,
'Test2': 3.0,
'Test3': 3.0,
'passing_test_0': 3.0,
'passing_test_1': 2.0,
'passing_test_2': 2.0,
'passing_test_3': 2.0,
'passing_test_4': 2.0,
'passing_test_5': 1.0,
'passing_test_6': 1.0,
'passing_test_7': 1.0,
'passing_test_8': 1.0,
'passing_test_9': 0.5,
}
}
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.close()
temp_file_name = temp_file.name
with open(temp_file_name, 'w') as f:
json.dump(mock_test_results, f)
return temp_file_name
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testSplittingShardsByTimes(self, _):
temp_file_name = self.writeMockTestResultsFile()
# It seems that the sorting order of the first four tests above is:
# passing_test_0, Test1, Test2, Test3
# This is probably because the relative order of the "fixed" tests
# (starting with "Test") and the generated ones ("passing_") is
# not well defined, and the sorting is stable afterward. The
# expectations have been adjusted for this fact.
try:
self.baseShardingTest(
4, 0, [],
['passing_test_0', 'passing_test_1',
'passing_test_5', 'passing_test_9'],
temp_file_name)
self.baseShardingTest(
4, 1, [],
['Test1', 'passing_test_2', 'passing_test_6'],
temp_file_name)
self.baseShardingTest(
4, 2, [],
['Test2', 'passing_test_3', 'passing_test_7'],
temp_file_name)
self.baseShardingTest(
4, 3, [],
['Test3', 'passing_test_4', 'passing_test_8'],
temp_file_name)
finally:
os.remove(temp_file_name)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testFilteringAfterSharding(self, _):
temp_file_name = self.writeMockTestResultsFile()
try:
self.baseShardingTest(
4, 1, [],
['Test1', 'passing_test_2', 'passing_test_6'],
temp_file_name,
opt_test_filter='(Test1|passing_test_2|passing_test_6)',
opt_filter_tests_after_sharding=True)
finally:
os.remove(temp_file_name)
@mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
def testMedianComputation(self, _):
self.assertEquals(2.0, browser_test_runner._MedianTestTime(
{'test1': 2.0, 'test2': 7.0, 'test3': 1.0}))
self.assertEquals(2.0, browser_test_runner._MedianTestTime(
{'test1': 2.0}))
self.assertEquals(0.0, browser_test_runner._MedianTestTime({}))
self.assertEqual(4.0, browser_test_runner._MedianTestTime(
{'test1': 2.0, 'test2': 6.0, 'test3': 1.0, 'test4': 8.0}))
class Algebra(
serially_executed_browser_test_case.SeriallyExecutedBrowserTestCase):
@classmethod
def GenerateTestCases_Simple(cls, options):
del options # Unused.
yield 'testOne', (1, 2)
yield 'testTwo', (3, 3)
def Simple(self, x, y):
self.assertEquals(x, y)
def TestNumber(self):
self.assertEquals(0, 1)
class Geometric(
serially_executed_browser_test_case.SeriallyExecutedBrowserTestCase):
@classmethod
def GenerateTestCases_Compare(cls, options):
del options # Unused.
yield 'testBasic', ('square', 'circle')
def Compare(self, x, y):
self.assertEquals(x, y)
def TestAngle(self):
self.assertEquals(90, 450)
class TestLoadAllTestModules(unittest.TestCase):
def testLoadAllTestsInModule(self):
tests = browser_test_runner.LoadAllTestsInModule(sys.modules[__name__])
self.assertEquals(sorted([t.id() for t in tests]),
['telemetry.testing.browser_test_runner_unittest.Algebra.TestNumber',
'telemetry.testing.browser_test_runner_unittest.Algebra.testOne',
'telemetry.testing.browser_test_runner_unittest.Algebra.testTwo',
'telemetry.testing.browser_test_runner_unittest.Geometric.TestAngle',
'telemetry.testing.browser_test_runner_unittest.Geometric.testBasic'])