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. 4import os 5import platform 6import stat 7import unittest 8 9from telemetry import decorators 10from telemetry.internal.platform.tracing_agent import chrome_tracing_agent 11from telemetry.internal.platform.tracing_agent import ( 12 chrome_tracing_devtools_manager) 13from telemetry.timeline import tracing_config 14 15from devil.android import device_utils 16 17 18class FakeTracingControllerBackend(object): 19 def __init__(self): 20 self.is_tracing_running = False 21 22 23class FakePlatformBackend(object): 24 def __init__(self): 25 self.tracing_controller_backend = FakeTracingControllerBackend() 26 27 def GetOSName(self): 28 return '' 29 30class FakeAndroidPlatformBackend(FakePlatformBackend): 31 def __init__(self): 32 super(FakeAndroidPlatformBackend, self).__init__() 33 devices = device_utils.DeviceUtils.HealthyDevices(None) 34 self.device = devices[0] 35 36 def GetOSName(self): 37 return 'android' 38 39class FakeDesktopPlatformBackend(FakePlatformBackend): 40 def GetOSName(self): 41 system = platform.system() 42 if system == 'Linux': 43 return 'linux' 44 if system == 'Darwin': 45 return 'mac' 46 if system == 'Windows': 47 return 'win' 48 49 50class FakeContextMap(object): 51 def __init__(self, contexts): 52 self.contexts = contexts 53 54 55class FakeDevtoolsClient(object): 56 def __init__(self, remote_port): 57 self.is_alive = True 58 self.is_tracing_running = False 59 self.remote_port = remote_port 60 self.will_raise_exception_in_stop_tracing = False 61 62 def IsAlive(self): 63 return self.is_alive 64 65 def StartChromeTracing(self, trace_options, filter_string, timeout=10): 66 del trace_options, filter_string, timeout # unused 67 self.is_tracing_running = True 68 69 def StopChromeTracing(self, trace_data_builder): 70 del trace_data_builder # unused 71 self.is_tracing_running = False 72 if self.will_raise_exception_in_stop_tracing: 73 raise Exception 74 75 def IsChromeTracingSupported(self): 76 return True 77 78 def GetUpdatedInspectableContexts(self): 79 return FakeContextMap([]) 80 81 82class ChromeTracingAgentTest(unittest.TestCase): 83 def setUp(self): 84 self.platform1 = FakePlatformBackend() 85 self.platform2 = FakePlatformBackend() 86 self.platform3 = FakePlatformBackend() 87 88 def StartTracing(self, platform_backend, enable_chrome_trace=True): 89 assert chrome_tracing_agent.ChromeTracingAgent.IsSupported(platform_backend) 90 agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) 91 config = tracing_config.TracingConfig() 92 config.tracing_category_filter.AddIncludedCategory('foo') 93 config.enable_chrome_trace = enable_chrome_trace 94 agent._platform_backend.tracing_controller_backend.is_tracing_running = True 95 agent._test_config = config 96 agent.StartAgentTracing(config, 10) 97 return agent 98 99 def FlushTracing(self, agent): 100 agent.FlushAgentTracing(agent._test_config, 10, None) 101 102 def StopTracing(self, agent): 103 agent._platform_backend.tracing_controller_backend.is_tracing_running = ( 104 False) 105 agent.StopAgentTracing(None) 106 107 def testRegisterDevtoolsClient(self): 108 chrome_tracing_devtools_manager.RegisterDevToolsClient( 109 FakeDevtoolsClient(1), self.platform1) 110 chrome_tracing_devtools_manager.RegisterDevToolsClient( 111 FakeDevtoolsClient(2), self.platform1) 112 chrome_tracing_devtools_manager.RegisterDevToolsClient( 113 FakeDevtoolsClient(3), self.platform1) 114 115 tracing_agent_of_platform1 = self.StartTracing(self.platform1) 116 117 chrome_tracing_devtools_manager.RegisterDevToolsClient( 118 FakeDevtoolsClient(4), self.platform1) 119 chrome_tracing_devtools_manager.RegisterDevToolsClient( 120 FakeDevtoolsClient(5), self.platform2) 121 122 self.StopTracing(tracing_agent_of_platform1) 123 chrome_tracing_devtools_manager.RegisterDevToolsClient( 124 FakeDevtoolsClient(6), self.platform1) 125 126 def testIsSupportWithoutStartupTracingSupport(self): 127 self.assertFalse( 128 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform1)) 129 self.assertFalse( 130 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform2)) 131 self.assertFalse( 132 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform3)) 133 134 devtool1 = FakeDevtoolsClient(1) 135 devtool2 = FakeDevtoolsClient(2) 136 chrome_tracing_devtools_manager.RegisterDevToolsClient( 137 devtool1, self.platform1) 138 chrome_tracing_devtools_manager.RegisterDevToolsClient( 139 devtool2, self.platform2) 140 devtool2.is_alive = False 141 142 # Chrome tracing is only supported on platform 1 since only platform 1 has 143 # an alive devtool. 144 self.assertTrue( 145 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform1)) 146 self.assertFalse( 147 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform2)) 148 self.assertFalse( 149 chrome_tracing_agent.ChromeTracingAgent.IsSupported(self.platform3)) 150 151 @decorators.Enabled('linux', 'mac', 'win') 152 def testIsSupportOnDesktopPlatform(self): 153 # Chrome tracing is always supported on desktop platforms because of startup 154 # tracing. 155 desktop_platform = FakeDesktopPlatformBackend() 156 self.assertTrue( 157 chrome_tracing_agent.ChromeTracingAgent.IsSupported(desktop_platform)) 158 159 devtool = FakeDevtoolsClient(1) 160 chrome_tracing_devtools_manager.RegisterDevToolsClient( 161 devtool, desktop_platform) 162 self.assertTrue( 163 chrome_tracing_agent.ChromeTracingAgent.IsSupported(desktop_platform)) 164 165 def testStartAndStopTracing(self): 166 devtool1 = FakeDevtoolsClient(1) 167 devtool2 = FakeDevtoolsClient(2) 168 devtool3 = FakeDevtoolsClient(3) 169 devtool4 = FakeDevtoolsClient(2) 170 # Register devtools 1, 2, 3 on platform1 and devtool 4 on platform 2 171 chrome_tracing_devtools_manager.RegisterDevToolsClient( 172 devtool1, self.platform1) 173 chrome_tracing_devtools_manager.RegisterDevToolsClient( 174 devtool2, self.platform1) 175 chrome_tracing_devtools_manager.RegisterDevToolsClient( 176 devtool3, self.platform1) 177 chrome_tracing_devtools_manager.RegisterDevToolsClient( 178 devtool4, self.platform2) 179 devtool2.is_alive = False 180 181 tracing_agent1 = self.StartTracing(self.platform1) 182 with self.assertRaises(chrome_tracing_agent.ChromeTracingStartedError): 183 self.StartTracing(self.platform1) 184 185 self.assertTrue(devtool1.is_tracing_running) 186 self.assertFalse(devtool2.is_tracing_running) 187 self.assertTrue(devtool3.is_tracing_running) 188 # Devtool 4 shouldn't have tracing started although it has the same remote 189 # port as devtool 2 190 self.assertFalse(devtool4.is_tracing_running) 191 192 self.StopTracing(tracing_agent1) 193 self.assertFalse(devtool1.is_tracing_running) 194 self.assertFalse(devtool2.is_tracing_running) 195 self.assertFalse(devtool3.is_tracing_running) 196 self.assertFalse(devtool4.is_tracing_running) 197 # Test that it should be ok to start & stop tracing on platform1 again. 198 tracing_agent1 = self.StartTracing(self.platform1) 199 self.StopTracing(tracing_agent1) 200 201 tracing_agent2 = self.StartTracing(self.platform2) 202 self.assertTrue(devtool4.is_tracing_running) 203 self.StopTracing(tracing_agent2) 204 self.assertFalse(devtool4.is_tracing_running) 205 206 def testFlushTracing(self): 207 devtool1 = FakeDevtoolsClient(1) 208 devtool2 = FakeDevtoolsClient(2) 209 devtool3 = FakeDevtoolsClient(3) 210 devtool4 = FakeDevtoolsClient(2) 211 212 # Register devtools 1, 2, 3 on platform1 and devtool 4 on platform 2. 213 chrome_tracing_devtools_manager.RegisterDevToolsClient( 214 devtool1, self.platform1) 215 chrome_tracing_devtools_manager.RegisterDevToolsClient( 216 devtool2, self.platform1) 217 chrome_tracing_devtools_manager.RegisterDevToolsClient( 218 devtool3, self.platform1) 219 chrome_tracing_devtools_manager.RegisterDevToolsClient( 220 devtool4, self.platform2) 221 devtool2.is_alive = False 222 223 tracing_agent1 = self.StartTracing(self.platform1) 224 225 self.assertTrue(devtool1.is_tracing_running) 226 self.assertFalse(devtool2.is_tracing_running) 227 self.assertTrue(devtool3.is_tracing_running) 228 # Devtool 4 shouldn't have tracing started although it has the same remote 229 # port as devtool 2. 230 self.assertFalse(devtool4.is_tracing_running) 231 232 for _ in xrange(5): 233 self.FlushTracing(tracing_agent1) 234 self.assertTrue(devtool1.is_tracing_running) 235 self.assertFalse(devtool2.is_tracing_running) 236 self.assertTrue(devtool3.is_tracing_running) 237 self.assertFalse(devtool4.is_tracing_running) 238 239 self.StopTracing(tracing_agent1) 240 self.assertFalse(devtool1.is_tracing_running) 241 self.assertFalse(devtool2.is_tracing_running) 242 self.assertFalse(devtool3.is_tracing_running) 243 self.assertFalse(devtool4.is_tracing_running) 244 245 # Test that it is ok to start, flush & stop tracing on platform1 again. 246 tracing_agent1 = self.StartTracing(self.platform1) 247 self.FlushTracing(tracing_agent1) 248 self.StopTracing(tracing_agent1) 249 250 tracing_agent2 = self.StartTracing(self.platform2) 251 self.assertTrue(devtool4.is_tracing_running) 252 self.FlushTracing(tracing_agent2) 253 self.assertTrue(devtool4.is_tracing_running) 254 self.StopTracing(tracing_agent2) 255 self.assertFalse(devtool4.is_tracing_running) 256 257 def testExceptionRaisedInStopTracing(self): 258 devtool1 = FakeDevtoolsClient(1) 259 devtool2 = FakeDevtoolsClient(2) 260 # Register devtools 1, 2 on platform 1 261 chrome_tracing_devtools_manager.RegisterDevToolsClient( 262 devtool1, self.platform1) 263 chrome_tracing_devtools_manager.RegisterDevToolsClient( 264 devtool2, self.platform1) 265 tracing_agent1 = self.StartTracing(self.platform1) 266 267 self.assertTrue(devtool1.is_tracing_running) 268 self.assertTrue(devtool2.is_tracing_running) 269 270 devtool1.will_raise_exception_in_stop_tracing = True 271 with self.assertRaises(chrome_tracing_agent.ChromeTracingStoppedError): 272 self.StopTracing(tracing_agent1) 273 # Tracing is stopped on both devtools clients even if there is exception. 274 self.assertIsNone(tracing_agent1.trace_config) 275 self.assertFalse(devtool1.is_tracing_running) 276 self.assertFalse(devtool2.is_tracing_running) 277 278 devtool1.is_alive = False 279 devtool2.is_alive = False 280 # Register devtools 3 on platform 1 should not raise any exception. 281 devtool3 = FakeDevtoolsClient(3) 282 chrome_tracing_devtools_manager.RegisterDevToolsClient( 283 devtool3, self.platform1) 284 285 # Start & Stop tracing on platform 1 should work just fine. 286 tracing_agent2 = self.StartTracing(self.platform1) 287 self.StopTracing(tracing_agent2) 288 289 @decorators.Enabled('android') 290 def testCreateAndRemoveTraceConfigFileOnAndroid(self): 291 platform_backend = FakeAndroidPlatformBackend() 292 agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) 293 self.assertIsNone(agent.trace_config_file) 294 295 config = tracing_config.TracingConfig() 296 agent._CreateTraceConfigFile(config) 297 self.assertIsNotNone(agent.trace_config_file) 298 self.assertTrue(platform_backend.device.PathExists(agent.trace_config_file)) 299 config_file_str = platform_backend.device.ReadFile(agent.trace_config_file, 300 as_root=True) 301 self.assertEqual(agent._CreateTraceConfigFileString(config), 302 config_file_str.strip()) 303 304 config_file_path = agent.trace_config_file 305 agent._RemoveTraceConfigFile() 306 self.assertFalse(platform_backend.device.PathExists(config_file_path)) 307 self.assertIsNone(agent.trace_config_file) 308 # robust to multiple file removal 309 agent._RemoveTraceConfigFile() 310 self.assertFalse(platform_backend.device.PathExists(config_file_path)) 311 self.assertIsNone(agent.trace_config_file) 312 313 @decorators.Enabled('linux', 'mac', 'win') 314 def testCreateAndRemoveTraceConfigFileOnDesktop(self): 315 platform_backend = FakeDesktopPlatformBackend() 316 agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) 317 self.assertIsNone(agent.trace_config_file) 318 319 config = tracing_config.TracingConfig() 320 agent._CreateTraceConfigFile(config) 321 self.assertIsNotNone(agent.trace_config_file) 322 self.assertTrue(os.path.exists(agent.trace_config_file)) 323 self.assertTrue(os.stat(agent.trace_config_file).st_mode & stat.S_IROTH) 324 with open(agent.trace_config_file, 'r') as f: 325 config_file_str = f.read() 326 self.assertEqual(agent._CreateTraceConfigFileString(config), 327 config_file_str.strip()) 328 329 config_file_path = agent.trace_config_file 330 agent._RemoveTraceConfigFile() 331 self.assertFalse(os.path.exists(config_file_path)) 332 self.assertIsNone(agent.trace_config_file) 333 # robust to multiple file removal 334 agent._RemoveTraceConfigFile() 335 self.assertFalse(os.path.exists(config_file_path)) 336 self.assertIsNone(agent.trace_config_file) 337