1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import sys
6import unittest
7
8from telemetry.core.platform.profiler import vtune_profiler
9from telemetry.unittest import options_for_unittests
10from telemetry.unittest import simple_mock
11from telemetry.unittest import tab_test_case
12
13
14class MockPopen(object):
15  def __init__(self, returncode, stdout=None, stderr=None):
16    self.returncode = returncode
17    self.stdout = stdout
18    self.stderr = stderr
19
20  def communicate(self):
21    return (self.stdout, self.stderr)
22
23  def wait(self):
24    return self.returncode
25
26
27class MockSubprocess(object):
28  def __init__(self):
29    self.PIPE = simple_mock.MockObject()
30    self.STDOUT = simple_mock.MockObject()
31    self._num_collect_calls = 0
32    self._num_stop_calls = 0
33
34  @property
35  def num_collect_calls(self):
36    return self._num_collect_calls
37
38  @property
39  def num_stop_calls(self):
40    return self._num_stop_calls
41
42  def Popen(self, cmd, **_):
43    self._AnalyzeCommand(cmd)
44    return MockPopen(0)
45
46  def call(self, cmd):
47    self._AnalyzeCommand(cmd)
48
49  def _AnalyzeCommand(self, cmd):
50    if MockSubprocess._IsCollectCommand(cmd):
51      self._num_collect_calls += 1
52    elif MockSubprocess._IsStopCommand(cmd):
53      self._num_stop_calls += 1
54
55  @staticmethod
56  def _IsCollectCommand(cmd):
57    return '-collect' in cmd
58
59  @staticmethod
60  def _IsStopCommand(cmd):
61    try:
62      cmd_idx = cmd.index('-command') + 1
63      return cmd_idx < len(cmd) and cmd[cmd_idx] == 'stop'
64    except ValueError:
65      return False
66
67
68class TestVTuneProfiler(unittest.TestCase):
69
70  def testVTuneProfilerIsSupported(self):
71    options = options_for_unittests.GetCopy()
72
73    mock_subprocess = simple_mock.MockObject()
74    mock_subprocess.ExpectCall(
75        'Popen').WithArgs(simple_mock.DONT_CARE).WillReturn(MockPopen(0))
76    mock_subprocess.SetAttribute('PIPE', simple_mock.MockObject())
77    mock_subprocess.SetAttribute('STDOUT', simple_mock.MockObject())
78
79    real_subprocess = vtune_profiler.subprocess
80    vtune_profiler.subprocess = mock_subprocess
81
82    if options.browser_type.startswith('android'):
83      # On Android we're querying if 'su' is available.
84      mock_subprocess.ExpectCall('Popen').WithArgs(
85          simple_mock.DONT_CARE).WillReturn(MockPopen(0, 'su', None))
86
87    try:
88      self.assertTrue(
89          vtune_profiler.VTuneProfiler.is_supported(options.browser_type) or
90          sys.platform != 'linux2' or
91          options.browser_type.startswith('cros'))
92    finally:
93      vtune_profiler.subprocess = real_subprocess
94
95
96class TestVTuneProfilerTabTestCase(tab_test_case.TabTestCase):
97
98  def testVTuneProfiler(self):
99    mock_subprocess = MockSubprocess()
100    real_subprocess = vtune_profiler.subprocess
101    vtune_profiler.subprocess = mock_subprocess
102
103    try:
104      # pylint: disable=W0212
105      profiler = vtune_profiler.VTuneProfiler(self._browser._browser_backend,
106                                              self._browser._platform_backend,
107                                              'tmp',
108                                              {})
109      profiler.CollectProfile()
110      self.assertEqual(mock_subprocess.num_collect_calls,
111                       mock_subprocess.num_stop_calls)
112    finally:
113      vtune_profiler.subprocess = real_subprocess
114