blob: 5c13701f5b12b48e1f189f074dbe86ec93923496 [file] [log] [blame]
# Copyright (C) 2012 Google Inc. All rights reserved.
# Copyright (C) 2020 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import logging
import unittest
from webkitpy.common.host_mock import MockHost
from webkitpy.port.driver import DriverOutput
from webkitpy.port.test import TestPort
from webkitpy.performance_tests.perftest import PerfTest
from webkitpy.performance_tests.perftest import PerfTestMetric
from webkitpy.performance_tests.perftest import PerfTestFactory
from webkitpy.performance_tests.perftest import SingleProcessPerfTest
from webkitcorepy import OutputCapture
class MockPort(TestPort):
def __init__(self, custom_run_test=None):
super(MockPort, self).__init__(host=MockHost(), custom_run_test=custom_run_test)
class TestPerfTestMetric(unittest.TestCase):
def test_init_set_missing_unit(self):
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time', iterations=[1, 2, 3, 4, 5]).unit(), 'ms')
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'Malloc', iterations=[1, 2, 3, 4, 5]).unit(), 'bytes')
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'JSHeap', iterations=[1, 2, 3, 4, 5]).unit(), 'bytes')
def test_init_set_time_metric(self):
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time', 'ms').name(), 'Time')
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time', 'fps').name(), 'FrameRate')
self.assertEqual(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time', 'runs/s').name(), 'Runs')
def test_has_values(self):
self.assertFalse(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time').has_values())
self.assertTrue(PerfTestMetric(['some', 'test'], 'some/test.html', 'Time', iterations=[1]).has_values())
def test_append(self):
metric = PerfTestMetric(['some', 'test'], 'some/test.html', 'Time')
metric2 = PerfTestMetric(['some', 'test'], 'some/test.html', 'Time')
self.assertFalse(metric.has_values())
self.assertFalse(metric2.has_values())
metric.append_group([1])
self.assertTrue(metric.has_values())
self.assertFalse(metric2.has_values())
self.assertEqual(metric.grouped_iteration_values(), [[1]])
self.assertEqual(metric.flattened_iteration_values(), [1])
metric.append_group([2])
self.assertEqual(metric.grouped_iteration_values(), [[1], [2]])
self.assertEqual(metric.flattened_iteration_values(), [1, 2])
metric2.append_group([3])
self.assertTrue(metric2.has_values())
self.assertEqual(metric.flattened_iteration_values(), [1, 2])
self.assertEqual(metric2.flattened_iteration_values(), [3])
metric.append_group([4, 5])
self.assertEqual(metric.grouped_iteration_values(), [[1], [2], [4, 5]])
self.assertEqual(metric.flattened_iteration_values(), [1, 2, 4, 5])
class TestPerfTest(unittest.TestCase):
def _assert_results_are_correct(self, test, output):
test.run_single = lambda driver, path, time_out_ms: output
self.assertTrue(test.run(10))
subtests = test._metrics
self.assertEqual(list(map(lambda test: test['name'], subtests)), [None])
metrics = subtests[0]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), metrics)), ['Time'])
self.assertEqual(metrics[0].flattened_iteration_values(), [1080, 1120, 1095, 1101, 1104] * 4)
def test_parse_output(self):
output = DriverOutput("""
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", image=None, image_hash=None, audio=None)
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
self._assert_results_are_correct(test, output)
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), """RESULT some-test: Time= 1100.0 ms
median= 1101.0 ms, stdev= 13.3140211016 ms, min= 1080.0 ms, max= 1120.0 ms
""")
def test_parse_output_with_ignored_stdout(self):
output = DriverOutput("""
main frame - has 1 onunload handler(s)
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", image=None, image_hash=None, audio=None)
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
self._assert_results_are_correct(test, output)
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), """RESULT some-test: Time= 1100.0 ms
median= 1101.0 ms, stdev= 13.3140211016 ms, min= 1080.0 ms, max= 1120.0 ms
""")
def test_parse_output_with_ignored_stderr(self):
output = DriverOutput(":Time -> [1080, 1120, 1095, 1101, 1104] ms", image=None, image_hash=None, audio=None, error="""
Jan 22 14:09:24 WebKitTestRunner[1296] <Error>: CGContextSetFillColorWithColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Jan 22 14:09:24 WebKitTestRunner[1296] <Error>: CGContextSetStrokeColorWithColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Jan 22 14:09:24 WebKitTestRunner[1296] <Error>: CGContextGetCompositeOperation: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Jan 22 14:09:24 WebKitTestRunner[1296] <Error>: CGContextSetCompositeOperation: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Jan 22 14:09:24 WebKitTestRunner[1296] <Error>: CGContextFillRects: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
""")
class MockPortWithSierraName(MockPort):
def name(self):
return "mac-sierra"
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPortWithSierraName(), 'some-test', '/path/some-dir/some-test')
self._assert_results_are_correct(test, output)
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), """RESULT some-test: Time= 1100.0 ms
median= 1101.0 ms, stdev= 13.3140211016 ms, min= 1080.0 ms, max= 1120.0 ms
""")
def _assert_failed_on_line(self, output_text, expected_log):
output = DriverOutput(output_text, image=None, image_hash=None, audio=None)
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
test.run_single = lambda driver, path, time_out_ms: output
self.assertFalse(test._run_with_driver(None, None))
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), expected_log)
def test_parse_output_with_running_five_times(self):
self._assert_failed_on_line("""
Running 5 times
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", 'ERROR: Running 5 times\n')
def test_parse_output_with_detailed_info(self):
self._assert_failed_on_line("""
1: 1080 ms
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", 'ERROR: 1: 1080 ms\n')
def test_parse_output_with_statistics(self):
self._assert_failed_on_line("""
:Time -> [1080, 1120, 1095, 1101, 1104] ms
mean: 105 ms
""", 'ERROR: mean: 105 ms\n')
def test_parse_output_with_description(self):
output = DriverOutput("""
Description: this is a test description.
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", image=None, image_hash=None, audio=None)
test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
self._assert_results_are_correct(test, output)
self.assertEqual(test.description(), 'this is a test description.')
def test_parse_output_with_subtests(self):
output = DriverOutput("""
Description: this is a test description.
some test:Time -> [1, 2, 3, 4, 5] ms
some other test = else:Time -> [6, 7, 8, 9, 10] ms
some other test = else:Malloc -> [11, 12, 13, 14, 15] bytes
Array Construction, []:Time -> [11, 12, 13, 14, 15] ms
Concat String:Time -> [15163, 15304, 15386, 15608, 15622] ms
jQuery - addClass:Time -> [2785, 2815, 2826, 2841, 2861] ms
Dojo - div:only-child:Time -> [7825, 7910, 7950, 7958, 7970] ms
Dojo - div:nth-child(2n+1):Time -> [3620, 3623, 3633, 3641, 3658] ms
Dojo - div > div:Time -> [10158, 10172, 10180, 10183, 10231] ms
Dojo - div ~ div:Time -> [6673, 6675, 6714, 6848, 6902] ms
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", image=None, image_hash=None, audio=None)
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPort(), 'some-dir/some-test', '/path/some-dir/some-test')
test.run_single = lambda driver, path, time_out_ms: output
self.assertTrue(test.run(10))
subtests = test._metrics
self.assertEqual(list(map(lambda test: test['name'], subtests)), ['some test', 'some other test = else',
'Array Construction, []', 'Concat String', 'jQuery - addClass', 'Dojo - div:only-child',
'Dojo - div:nth-child(2n+1)', 'Dojo - div > div', 'Dojo - div ~ div', None])
some_test_metrics = subtests[0]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), some_test_metrics)), ['Time'])
self.assertEqual(some_test_metrics[0].path(), ['some-dir', 'some-test', 'some test'])
self.assertEqual(some_test_metrics[0].flattened_iteration_values(), [1, 2, 3, 4, 5] * 4)
some_other_test_metrics = subtests[1]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), some_other_test_metrics)), ['Time', 'Malloc'])
self.assertEqual(some_other_test_metrics[0].path(), ['some-dir', 'some-test', 'some other test = else'])
self.assertEqual(some_other_test_metrics[0].flattened_iteration_values(), [6, 7, 8, 9, 10] * 4)
self.assertEqual(some_other_test_metrics[1].path(), ['some-dir', 'some-test', 'some other test = else'])
self.assertEqual(some_other_test_metrics[1].flattened_iteration_values(), [11, 12, 13, 14, 15] * 4)
main_metrics = subtests[len(subtests) - 1]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), main_metrics)), ['Time'])
self.assertEqual(main_metrics[0].path(), ['some-dir', 'some-test'])
self.assertEqual(main_metrics[0].flattened_iteration_values(), [1080, 1120, 1095, 1101, 1104] * 4)
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), """DESCRIPTION: this is a test description.
RESULT some-dir: some-test: Time= 1100.0 ms
median= 1101.0 ms, stdev= 13.3140211016 ms, min= 1080.0 ms, max= 1120.0 ms
""")
def test_parse_output_with_subtests_and_total(self):
output = DriverOutput("""
:Time:Total -> [2324, 2328, 2345, 2314, 2312] ms
EmberJS-TodoMVC:Time:Total -> [1462, 1473, 1490, 1465, 1458] ms
EmberJS-TodoMVC/a:Time -> [1, 2, 3, 4, 5] ms
BackboneJS-TodoMVC:Time -> [862, 855, 855, 849, 854] ms
""", image=None, image_hash=None, audio=None)
with OutputCapture(level=logging.INFO) as captured:
test = PerfTest(MockPort(), 'some-dir/some-test', '/path/some-dir/some-test')
test.run_single = lambda driver, path, time_out_ms: output
self.assertTrue(test.run(10))
subtests = test._metrics
self.assertEqual(list(map(lambda test: test['name'], subtests)), [None, 'EmberJS-TodoMVC', 'EmberJS-TodoMVC/a', 'BackboneJS-TodoMVC'])
main_metrics = subtests[0]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), main_metrics)), ['Time'])
self.assertEqual(main_metrics[0].aggregator(), 'Total')
self.assertEqual(main_metrics[0].path(), ['some-dir', 'some-test'])
self.assertEqual(main_metrics[0].flattened_iteration_values(), [2324, 2328, 2345, 2314, 2312] * 4)
some_test_metrics = subtests[1]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), some_test_metrics)), ['Time'])
self.assertEqual(some_test_metrics[0].aggregator(), 'Total')
self.assertEqual(some_test_metrics[0].path(), ['some-dir', 'some-test', 'EmberJS-TodoMVC'])
self.assertEqual(some_test_metrics[0].flattened_iteration_values(), [1462, 1473, 1490, 1465, 1458] * 4)
some_test_metrics = subtests[2]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), some_test_metrics)), ['Time'])
self.assertEqual(some_test_metrics[0].aggregator(), None)
self.assertEqual(some_test_metrics[0].path(), ['some-dir', 'some-test', 'EmberJS-TodoMVC', 'a'])
self.assertEqual(some_test_metrics[0].flattened_iteration_values(), [1, 2, 3, 4, 5] * 4)
some_test_metrics = subtests[3]['metrics']
self.assertEqual(list(map(lambda metric: metric.name(), some_test_metrics)), ['Time'])
self.assertEqual(some_test_metrics[0].aggregator(), None)
self.assertEqual(some_test_metrics[0].path(), ['some-dir', 'some-test', 'BackboneJS-TodoMVC'])
self.assertEqual(some_test_metrics[0].flattened_iteration_values(), [862, 855, 855, 849, 854] * 4)
self.assertEqual(captured.stdout.getvalue(), '')
self.assertEqual(captured.stderr.getvalue(), '')
self.assertEqual(captured.root.log.getvalue(), """RESULT some-dir: some-test: Time= 2324.6 ms
median= 2324.0 ms, stdev= 12.1326007105 ms, min= 2312.0 ms, max= 2345.0 ms
""")
class TestSingleProcessPerfTest(unittest.TestCase):
def test_use_only_one_process(self):
called = [0]
def run_single(driver, path, time_out_ms):
called[0] += 1
return DriverOutput("""
Description: this is a test description.
:Time -> [1080, 1120, 1095, 1101, 1104] ms
""", image=None, image_hash=None, audio=None)
test = SingleProcessPerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
test.run_single = run_single
self.assertTrue(test.run(0))
self.assertEqual(called[0], 1)
class TestPerfTestFactory(unittest.TestCase):
def test_regular_test(self):
test = PerfTestFactory.create_perf_test(MockPort(), 'some-dir/some-test', '/path/some-dir/some-test')
self.assertEqual(test.__class__, PerfTest)