blob: 0c68face2c7d19a6aeb55399b38aa431b6747e85 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for tools.android.build_speed.benchmark."""
import contextlib
import json
import pathlib
import subprocess
import sys
import tempfile
import unittest
import unittest.mock
import benchmark
from pylib import constants
class TestBenchmarkScript(unittest.TestCase):
"""Unit tests for benchmark.py."""
@unittest.mock.patch('benchmark._terminate_build_server_if_needed')
@unittest.mock.patch('random.randint', return_value=123)
@unittest.mock.patch(
'time.time',
side_effect=[1.0, 3.5, 5.0, 10.0, 11.0, 13.0, 15.0, 20.5, 22.0, 25.0])
@unittest.mock.patch('subprocess.run')
@unittest.mock.patch('benchmark._emulator',
return_value=contextlib.nullcontext(
unittest.mock.Mock(serial='emulator-5554')))
def test_run_benchmarks(self, mock_emulator, mock_subprocess_run,
mock_time, mock_randint,
mock_terminate_build_server):
benchmarks_to_run = ['chrome_nosig']
gn_args = ['is_debug=true']
repeat = 1
change_file_path = (
benchmark._SRC_ROOT /
benchmark._BENCHMARK_FROM_NAME['chrome_nosig'].change_file)
original_content = change_file_path.read_text()
try:
with tempfile.TemporaryDirectory() as tmpdir:
out_dir = pathlib.Path(tmpdir)
timings = benchmark.run_benchmarks(
benchmarks_to_run,
gn_args,
out_dir,
'target',
repeat,
emulator_avd_name='emulator.avd',
dry_run=False)
self.assertEqual(timings['gn_gen'], [2.5])
self.assertEqual(timings['chrome_nosig_compile'], [5.5])
self.assertEqual(timings['chrome_nosig_install'], [3.0])
finally:
# Ensure the file is restored even if the test fails.
change_file_path.write_text(original_content)
self.assertEqual(change_file_path.read_text(), original_content)
@unittest.mock.patch('builtins.print')
@unittest.mock.patch('benchmark.run_benchmarks')
def test_main_logic(self, mock_run_benchmarks, mock_print):
mock_run_benchmarks.return_value = {
'gn_gen': [1.23],
'chrome_nosig_compile': [10.56]
}
with tempfile.TemporaryDirectory() as tmpdir:
constants.SetOutputDirectory(tmpdir)
# Test default args and quiet mode.
with unittest.mock.patch(
'sys.argv', ['benchmark.py', 'chrome_nosig', '--quiet']):
benchmark.main()
args, _kwargs = mock_run_benchmarks.call_args
expected_gn_args = [
'target_os="android"',
'use_remoteexec=true',
'android_static_analysis="build_server"',
'incremental_install=true',
'target_cpu="x86"',
]
self.assertEqual(args[1], expected_gn_args)
# The real output is tested in the next block, this just clears
# the mock calls.
mock_print.reset_mock()
# Test --no-server and output printing.
with unittest.mock.patch(
'sys.argv',
['benchmark.py', 'chrome_nosig', '--no-server']):
benchmark.main()
args, _kwargs = mock_run_benchmarks.call_args
expected_gn_args = [
'target_os="android"',
'use_remoteexec=true',
'android_static_analysis="on"',
'incremental_install=true',
'target_cpu="x86"',
]
self.assertEqual(args[1], expected_gn_args)
# Get the printed output from the mock.
printed_output = '\n'.join(c.args[0]
for c in mock_print.call_args_list)
expected_output = (
'Summary\n'
'emulator: None\n'
'gn args: target_os="android" use_remoteexec=true '
'android_static_analysis="on" '
'incremental_install=true target_cpu="x86"\n'
'target: chrome_public_apk\n'
'gn_gen: 1.2s\n'
'chrome_nosig_compile: 10.6s')
self.assertEqual(printed_output, expected_output)
@unittest.mock.patch('builtins.print')
@unittest.mock.patch('benchmark.run_benchmarks')
def test_main_json_output(self, mock_run_benchmarks, mock_print):
mock_run_benchmarks.return_value = {
'gn_gen': [1.23],
'chrome_nosig_compile': [10.56],
}
with tempfile.TemporaryDirectory() as tmpdir:
constants.SetOutputDirectory(tmpdir)
with unittest.mock.patch('sys.argv', [
'benchmark.py', 'chrome_nosig', '--json', '--emulator',
'fake_emu'
]):
benchmark.main()
# Verify run_benchmarks call
args, _kwargs = mock_run_benchmarks.call_args
self.assertEqual(args[0], ['chrome_nosig'])
self.assertEqual(args[5], 'fake_emu')
# Verify JSON output
printed_output = mock_print.call_args.args[0]
parsed_json = json.loads(printed_output)
expected_json = [
{
'name':
'gn_gen',
'timings': [1.23],
'emulator':
'fake_emu',
'gn_args': [
'target_os="android"',
'use_remoteexec=true',
'android_static_analysis="build_server"',
'incremental_install=true',
'target_cpu="x64"',
],
'target':
'chrome_public_apk',
},
{
'name':
'chrome_nosig_compile',
'timings': [10.56],
'emulator':
'fake_emu',
'gn_args': [
'target_os="android"',
'use_remoteexec=true',
'android_static_analysis="build_server"',
'incremental_install=true',
'target_cpu="x64"',
],
'target':
'chrome_public_apk',
},
]
self.assertEqual(parsed_json, expected_json)
@unittest.mock.patch('builtins.print')
@unittest.mock.patch('benchmark.run_benchmarks')
def test_main_dry_run(self, mock_run_benchmarks, mock_print):
with tempfile.TemporaryDirectory() as tmpdir:
constants.SetOutputDirectory(tmpdir)
with unittest.mock.patch(
'sys.argv', ['benchmark.py', 'chrome_nosig', '--dry-run']):
benchmark.main()
# Verify run_benchmarks was called with dry_run=True
_args, kwargs = mock_run_benchmarks.call_args
self.assertTrue(kwargs['dry_run'])
if __name__ == '__main__':
unittest.main()