#!/usr/bin/env vpython3 # # Copyright 2019 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. """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()