def pid(self): try: # Although there might be multiple processes sharing the same name as # the browser app, the browser process is the only one being a direct # descendant of an Android zygote. (See crbug.com/785446) zygotes = self.device.ListProcesses('zygote') zygote_pids = set(p.pid for p in zygotes) assert zygote_pids, 'No Android zygote found' processes = self.device.ListProcesses( self._backend_settings.package) pids = [] for process in processes: if (process.name == self._backend_settings.package and process.ppid in zygote_pids): pids.append(process.pid) assert len(pids) <= 1, 'Found too many browsers: %r' % pids except Exception as exc: # Re-raise as an AppCrashException to get further diagnostic information. # In particular we also get the values of all local variables above. raise exceptions.AppCrashException( self.browser, 'Error getting browser PID: %s' % exc) if not pids: raise exceptions.BrowserGoneException(self.browser) return pids[0]
def testReturnCodeCaughtException(self): fake_benchmark = FakeBenchmark(stories=[ test_stories.DummyStory( 'story', run_side_effect=exceptions.AppCrashException())]) options = self.GetFakeBrowserOptions() return_code = story_runner.RunBenchmark(fake_benchmark, options) self.assertEqual(return_code, exit_codes.TEST_FAILURE)
def testRunStoryAndProcessErrorIfNeeded_tryAppCrash(self): tmp = tempfile.NamedTemporaryFile(delete=False) tmp.close() temp_file_path = tmp.name fake_app = fakes.FakeApp() fake_app.recent_minidump_path = temp_file_path try: app_crash_exception = exceptions.AppCrashException(fake_app, msg='foo') root_mock = self._CreateErrorProcessingMock( method_exceptions={'state.WillRunStory': app_crash_exception}) with self.assertRaises(exceptions.AppCrashException): story_runner._RunStoryAndProcessErrorIfNeeded( root_mock.story, root_mock.results, root_mock.state, root_mock.test, self.finder_options) self.assertListEqual(root_mock.method_calls, [ mock.call.results.CreateArtifact('logs.txt'), mock.call.test.WillRunStory(root_mock.state.platform, root_mock.story), mock.call.state.WillRunStory(root_mock.story), mock.call.state.DumpStateUponStoryRunFailure( root_mock.results), mock.call.results.Fail( 'Exception raised running %s' % root_mock.story.name), mock.call.test.DidRunStory(root_mock.state.platform, root_mock.results), mock.call.state.DidRunStory(root_mock.results), ]) finally: os.remove(temp_file_path)
def testAppCrashThenRaiseInTearDown_Interrupted( self, tear_down_state, dump_state_upon_story_run_failure): class TearDownStateException(Exception): pass tear_down_state.side_effect = TearDownStateException() root_mock = mock.Mock() root_mock.attach_mock(tear_down_state, 'state.TearDownState') root_mock.attach_mock(dump_state_upon_story_run_failure, 'state.DumpStateUponStoryRunFailure') self.RunStories([ test_stories.DummyStory( 'foo', run_side_effect=exceptions.AppCrashException(msg='crash!')), test_stories.DummyStory('bar')]) self.assertEqual([call[0] for call in root_mock.mock_calls], [ 'state.DumpStateUponStoryRunFailure', # This tear down happens because of the app crash. 'state.TearDownState', # This one happens since state must be re-created to check whether # later stories should be skipped or unexpectedly skipped. Then # state is torn down normally at the end of the runs. 'state.TearDownState' ]) test_results = self.ReadTestResults() self.assertEqual(len(test_results), 2) # First story unexpectedly failed with AppCrashException. self.assertEqual(test_results[0]['status'], 'FAIL') self.assertFalse(test_results[0]['expected']) # Second story unexpectedly skipped due to exception during tear down. self.assertEqual(test_results[1]['status'], 'SKIP') self.assertFalse(test_results[1]['expected'])
def _ConvertExceptionFromInspectorWebsocket(self, error): """Converts an Exception from inspector_websocket. This method always raises a Telemetry exception. It appends debugging information. The exact exception raised depends on |error|. Args: error: An instance of socket.error or inspector_websocket.WebSocketException. Raises: exceptions.TimeoutException: A timeout occurred. exceptions.DevtoolsTargetCrashException: On any other error, the most likely explanation is that the devtool's target crashed. """ # pylint: disable=redefined-variable-type if isinstance(error, inspector_websocket.WebSocketException): new_error = exceptions.TimeoutException() new_error.AddDebuggingMessage(exceptions.AppCrashException( self.app, 'The app is probably crashed:\n')) else: new_error = exceptions.DevtoolsTargetCrashException(self.app) original_error_msg = 'Original exception:\n' + str(error) new_error.AddDebuggingMessage(original_error_msg) self._AddDebuggingInformation(new_error) raise new_error, None, sys.exc_info()[2]
def testAppCrashExceptionCausesFailure(self): self.RunStories([test_stories.DummyStory( 'story', run_side_effect=exceptions.AppCrashException(msg='App Foo crashes'))]) test_results = self.ReadTestResults() self.assertEqual(['FAIL'], [test['status'] for test in test_results]) self.assertIn('App Foo crashes', sys.stderr.getvalue())
def DumpMemory(self, timeout=None): try: return self._browser_backend.DumpMemory(timeout=timeout) except tracing_backend.TracingUnrecoverableException: logging.exception('Failed to record memory dump due to exception:') # Re-raise as an AppCrashException to obtain further debug information # about the browser state. raise exceptions.AppCrashException( app=self, msg='Browser failed to record memory dump.')
def testNoScreenShotTakenForFailedPageDueToNoSupport(self): # The default "FakePlatform" does not support taking screenshots. self.assertFalse(self.fake_platform.CanTakeScreenshot()) self.options.browser_options.take_screenshot_for_failed_page = True story_set = test_stories.SinglePageStorySet( story_run_side_effect=exceptions.AppCrashException(msg='fake crash')) results = self.RunStorySetAndGetResults(story_set) self.assertEqual(results['status'], 'FAIL') self.assertNotIn('screenshot.png', results['outputArtifacts'])
def processes(self): try: zygotes = self.device.ListProcesses('zygote') zygote_pids = set(p.pid for p in zygotes) assert zygote_pids, 'No Android zygote found' processes = self.device.ListProcesses(self._backend_settings.package) return [p for p in processes if p.ppid in zygote_pids] except Exception as exc: # Re-raise as an AppCrashException to get further diagnostic information. # In particular we also get the values of all local variables above. raise exceptions.AppCrashException( self.browser, 'Error getting browser PIDs: %s' % exc)
def pid(self): try: pid = self.device.GetApplicationPids( self._backend_settings.package, at_most_one=True) except device_errors.CommandFailedError as exc: logging.warning('Dumping output of "ps" command for diagnosis:') for line in self.device.RunShellCommand(['ps']): logging.warning('- %s', line) # This may happen if we end up with two PIDs for the browser process. # Re-raise as an AppCrashException to get further debug information. raise exceptions.AppCrashException( self.browser, 'Error getting browser PID: %s' % exc) if not pid: raise exceptions.BrowserGoneException(self.browser) return int(pid)
def testScreenShotTakenForFailedPageOnSupportedPlatform(self): expected_png_base64 = ('iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91' 'JpzAAAAFklEQVR4Xg3EAQ0AAABAMP1LY3YI7l8l6A' 'T8tgwbJAAAAABJRU5ErkJggg==') self.fake_platform.screenshot_png_data = expected_png_base64 # After setting up some fake data, now the platform supports screenshots. self.assertTrue(self.fake_platform.CanTakeScreenshot()) self.options.browser_options.take_screenshot_for_failed_page = True story_set = test_stories.SinglePageStorySet( story_run_side_effect=exceptions.AppCrashException(msg='fake crash')) results = self.RunStorySetAndGetResults(story_set) self.assertEqual(results['status'], 'FAIL') self.assertIn('screenshot.png', results['outputArtifacts']) actual_screenshot_img = image_util.FromPngFile( results['outputArtifacts']['screenshot.png']['filePath']) self.assertTrue( image_util.AreEqual( image_util.FromBase64Png(expected_png_base64), actual_screenshot_img))
def WillRunUserStory(self, user_storyz): raise exceptions.AppCrashException('App Foo crashes')
def WillRunStory(self, story): raise exceptions.AppCrashException(msg='App Foo crashes')