#!/usr/bin/env vpython3
#
# Copyright 2019 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 run_simpleperf.py"""
import os
import unittest
import mock # pylint: disable=import-error
from run_simpleperf import SimplePerfRunner
from run_simpleperf import StackAddressInterpreter
_EXAMPLE_WEBVIEW_PACKAGE_NAME = "com.google.android.webview"
_EXAMPLE_STACK_SCRIPT_INPUT = [
("11-15 00:00:00.000 11111 11111 E chromium: #00 0x0000001111111111 "
"/data/app/com.google.android.webview--8E2vMMZTpLVeEKY7ZgoHQ=="
"/lib/arm64/libwebviewchromium.so+0x00000000083a4db8"),
("11-15 00:00:00.000 11111 11111 E chromium: #00 0x0000001111111111 "
"/data/app/com.google.android.webview--8E2vMMZTpLVeEKY7ZgoHQ=="
"/lib/arm64/libwebviewchromium.so+0x00000000083db114"),
("11-15 00:00:00.000 11111 11111 E chromium: #00 0x0000001111111111 "
"/data/app/com.google.android.webview--8E2vMMZTpLVeEKY7ZgoHQ=="
"/lib/arm64/libwebviewchromium.so+0x000000000abcdef0")]
_EXAMPLE_STACK_SCRIPT_OUTPUT = [
"Stack Trace:",
" RELADDR FUNCTION",
(" 00000000083a4db8 mojo::core::ports::(anonymous namespace)::UpdateTLS("
"mojo::core::ports::PortLocker*, mojo::core::ports::PortLocker*) "
"../../mojo/core/ports/port_locker.cc:26:3"),
"",
"-----------------------------------------------------",
"",
"Stack Trace:",
" RELADDR FUNCTION",
(" 00000000083db114 viz::GLRenderer::SetUseProgram(viz::ProgramKey "
"const&, gfx::ColorSpace const&, gfx::ColorSpace const&) "
"../../components/viz/service/display/gl_renderer.cc:3267:14"),
"",
"-----------------------------------------------------"]
_ADDRESSES = ['83a4db8', '83db114', 'abcdef0'] # 3rd one is ignored
_WEBVIEW_LIB_NAME = 'libwebviewchromium.so'
_WEBVIEW_LIB_PATH = (
'/data/app/com.google.android.webview'
'--8E2vMMZTpLVeEKY7ZgoHQ==/lib/arm64/libwebviewchromium.so')
_EXAMPLE_INTERPRETER_OUTPUT = [
('83a4db8',
('mojo::core::ports::(anonymous namespace)::UpdateTLS('
'mojo::core::ports::PortLocker*, mojo::core::ports::PortLocker*)')),
('83db114',
('viz::GLRenderer::SetUseProgram(viz::ProgramKey const&, '
'gfx::ColorSpace const&, gfx::ColorSpace const&)'))]
_EXAMPLE_INTERPRETER_OUTPUT_WITH_FILE_NAME_LINE = [
('83a4db8',
('mojo::core::ports::(anonymous namespace)::UpdateTLS('
'mojo::core::ports::PortLocker*, mojo::core::ports::PortLocker*)'
' | ../../mojo/core/ports/port_locker.cc:26:3')),
('83db114',
('viz::GLRenderer::SetUseProgram(viz::ProgramKey const&, '
'gfx::ColorSpace const&, gfx::ColorSpace const&)'
' | ../../components/viz/service/display/gl_renderer.cc:3267:14'))]
_MOCK_ORIGINAL_REPORT = [
'"442": {"l": 28, "f": "libwebviewchromium.so[+3db7d84]"},',
'"443": {"l": 28, "f": "libwebviewchromium.so[+3db7a5c]"},',
'"444": {"l": 28, "f": "libwebviewchromium.so[+aaaaaaa]"},'
]
_MOCK_ADDRESSES = ['3db7d84', '3db7a5c', 'aaaaaaa']
_MOCK_ADDRESS_FUNCTION_NAME_PAIRS = [
('3db7d84', 'MyClass::FirstMethod(const char*)'),
('3db7a5c', 'MyClass::SecondMethod(int)')]
_MOCK_FINAL_REPORT = [
('"442": {"l": 28, "f": "libwebviewchromium.so[MyClass::'
'FirstMethod(const char*)]"},'),
('"443": {"l": 28, "f": "libwebviewchromium.so[MyClass::'
'SecondMethod(int)]"},'),
('"444": {"l": 28, "f": "libwebviewchromium.so[+aaaaaaa]"},')
]
class _RunSimpleperfTest(unittest.TestCase):
"""Unit tests for the run_simpleperf module. """
def _AssertFileLines(self, mock_open, expected_lines):
handle = mock_open()
# Get 'str1', 'str2', ... from the call to f.write(str_i + '\n') which is
# saved as [(str1 + '\n'), (str2 + '\n'), ...].
actual_lines = [args[0][:-1] for (args, _) in
handle.write.call_args_list]
self.assertEqual(expected_lines, actual_lines)
def setUp(self):
self.tmp_dir = '/tmp' # the actual directory won't be used in this test.
self.args = mock.Mock(
report_path=os.path.join(self.tmp_dir, 'report.html'),
show_file_line=False)
self.device = mock.Mock()
self.stack_address_interpreter = StackAddressInterpreter(self.args,
self.tmp_dir)
self.simple_perf_runner = SimplePerfRunner(
self.device, self.args, self.tmp_dir, self.stack_address_interpreter)
@mock.patch('run_simpleperf.open', new_callable=mock.mock_open)
def testStackAddressInterpreter(self, mock_open):
StackAddressInterpreter.RunStackScript = mock.Mock(
return_value=_EXAMPLE_STACK_SCRIPT_OUTPUT)
self.assertEqual(
_EXAMPLE_INTERPRETER_OUTPUT,
self.stack_address_interpreter.Interpret(_ADDRESSES, _WEBVIEW_LIB_PATH))
self._AssertFileLines(mock_open, _EXAMPLE_STACK_SCRIPT_INPUT)
@mock.patch('run_simpleperf.open', new_callable=mock.mock_open)
def testStackAddressInterpreterWithFileNameLine(self, mock_open):
self.args.show_file_line = True
StackAddressInterpreter.RunStackScript = mock.Mock(
return_value=_EXAMPLE_STACK_SCRIPT_OUTPUT)
self.assertEqual(
_EXAMPLE_INTERPRETER_OUTPUT_WITH_FILE_NAME_LINE,
self.stack_address_interpreter.Interpret(_ADDRESSES, _WEBVIEW_LIB_PATH))
self._AssertFileLines(mock_open, _EXAMPLE_STACK_SCRIPT_INPUT)
def testSimplePerfRunner_CollectAddresses(self):
addresses = self.simple_perf_runner.CollectAddresses(
_MOCK_ORIGINAL_REPORT, 'libwebviewchromium.so')
self.assertEqual(set(_MOCK_ADDRESSES), addresses)
def testSimplePerfRunner_ReplaceAddresses(self):
postprocessed_report = (
self.simple_perf_runner.ReplaceAddressesWithFunctionInfos(
_MOCK_ORIGINAL_REPORT, _MOCK_ADDRESS_FUNCTION_NAME_PAIRS,
'libwebviewchromium.so'))
self.assertEqual(_MOCK_FINAL_REPORT, postprocessed_report)
@mock.patch('run_simpleperf.open', new_callable=mock.mock_open)
def testSimplePerfRunner_Run(self, mock_open):
self.stack_address_interpreter.Interpret = mock.Mock(
return_value=_MOCK_ADDRESS_FUNCTION_NAME_PAIRS)
SimplePerfRunner.RunSimplePerf = mock.Mock()
SimplePerfRunner.RunPackageCompile = mock.Mock()
SimplePerfRunner.GetOriginalReportHtml = mock.Mock(
return_value=_MOCK_ORIGINAL_REPORT)
self.simple_perf_runner.GetCurrentWebViewProvider = mock.Mock(
return_value=_EXAMPLE_WEBVIEW_PACKAGE_NAME)
self.simple_perf_runner.GetWebViewLibraryNameAndPath = mock.Mock(
return_value=(_WEBVIEW_LIB_NAME, _WEBVIEW_LIB_PATH))
self.simple_perf_runner.Run()
self._AssertFileLines(mock_open, _MOCK_FINAL_REPORT)
if __name__ == '__main__':
unittest.main()