Index: tools/telemetry/telemetry/user_story/user_story_runner.py |
diff --git a/tools/telemetry/telemetry/user_story/user_story_runner.py b/tools/telemetry/telemetry/user_story/user_story_runner.py |
index f482c09d80b00f2531e64356bc3753817b57da50..0358c929b032dd06aaa3c82d91a0231f23de4549 100644 |
--- a/tools/telemetry/telemetry/user_story/user_story_runner.py |
+++ b/tools/telemetry/telemetry/user_story/user_story_runner.py |
@@ -79,7 +79,6 @@ def ProcessCommandLineArgs(parser, args): |
def _RunUserStoryAndProcessErrorIfNeeded( |
test, expectations, user_story, results, state): |
- expectation = None |
def ProcessError(): |
if expectation == 'fail': |
msg = 'Expected exception while running %s' % user_story.display_name |
@@ -87,8 +86,8 @@ def _RunUserStoryAndProcessErrorIfNeeded( |
else: |
msg = 'Exception while running %s' % user_story.display_name |
results.AddValue(failure.FailureValue(user_story, sys.exc_info())) |
- |
try: |
+ expectation = None |
state.WillRunUserStory(user_story) |
expectation, skip_value = state.GetTestExpectationAndSkipValue(expectations) |
if expectation == 'skip': |
@@ -96,19 +95,16 @@ def _RunUserStoryAndProcessErrorIfNeeded( |
results.AddValue(skip_value) |
return |
state.RunUserStory(results) |
- except page_test.TestNotSupportedOnPlatformFailure: |
- raise |
except (page_test.Failure, util.TimeoutException, exceptions.LoginException, |
exceptions.ProfilingException): |
ProcessError() |
except exceptions.AppCrashException: |
ProcessError() |
- state.TearDownState(results) |
if test.is_multi_tab_test: |
logging.error('Aborting multi-tab test after browser or tab crashed at ' |
'user story %s' % user_story.display_name) |
test.RequestExit() |
- return |
+ raise |
except page_action.PageActionNotSupported as e: |
results.AddValue( |
skip.SkipValue(user_story, 'Unsupported page action: %s' % e)) |
@@ -117,8 +113,15 @@ def _RunUserStoryAndProcessErrorIfNeeded( |
logging.warning( |
'%s was expected to fail, but passed.\n', user_story.display_name) |
finally: |
- state.DidRunUserStory(results) |
- |
+ has_existing_exception = sys.exc_info() is not None |
+ try: |
+ state.DidRunUserStory(results) |
+ except Exception: |
+ if not has_existing_exception: |
+ raise |
+ # Print current exception and propagate existing exception. |
+ exception_formatter.PrintFormattedException( |
+ msg='Exception from DidRunUserStory: ') |
@decorators.Cache |
def _UpdateUserStoryArchivesIfChanged(user_story_set): |
@@ -190,7 +193,12 @@ def GetUserStoryGroupsWithSameSharedUserStoryClass(user_story_set): |
def Run(test, user_story_set, expectations, finder_options, results): |
- """Runs a given test against a given page_set with the given options.""" |
+ """Runs a given test against a given page_set with the given options. |
+ |
+ Stop execution for unexpected exceptions such as KeyboardInterrupt. |
+ We "white list" certain exceptions for which the user story runner |
+ can continue running the remaining user stories. |
+ """ |
test.ValidatePageSet(user_story_set) |
# Reorder page set based on options. |
@@ -227,39 +235,63 @@ def Run(test, user_story_set, expectations, finder_options, results): |
for group in user_story_groups: |
state = None |
try: |
- state = group.shared_user_story_state_class( |
- test, finder_options, user_story_set) |
for _ in xrange(finder_options.pageset_repeat): |
for user_story in group.user_stories: |
- if test.IsExiting(): |
- break |
for _ in xrange(finder_options.page_repeat): |
+ if test.IsExiting(): |
+ break |
+ if not state: |
+ state = group.shared_user_story_state_class( |
+ test, finder_options, user_story_set) |
results.WillRunPage(user_story) |
try: |
_WaitForThermalThrottlingIfNeeded(state.platform) |
_RunUserStoryAndProcessErrorIfNeeded( |
test, expectations, user_story, results, state) |
- except Exception: |
- # Tear down & restart the state for unhandled exceptions thrown by |
- # _RunUserStoryAndProcessErrorIfNeeded. |
- results.AddValue(failure.FailureValue(user_story, sys.exc_info())) |
- state.TearDownState(results) |
- state = group.shared_user_story_state_class( |
- test, finder_options, user_story_set) |
+ except exceptions.AppCrashException: |
+ # Catch AppCrashException to give the story a chance to retry. |
+ # The retry is enabled by tearing down the state and creating |
+ # a new state instance in the next iteration. |
+ if not test.IsExiting(): |
+ try: |
+ # If TearDownState raises, do not catch the exception. |
+ # (The AppCrashException was saved as a failure value.) |
+ state.TearDownState(results) |
+ finally: |
+ # Later finally-blocks use state, so ensure it is cleared. |
+ state = None |
finally: |
- _CheckThermalThrottling(state.platform) |
- discard_run = (test.discard_first_result and |
- user_story not in |
- user_story_with_discarded_first_results) |
- if discard_run: |
- user_story_with_discarded_first_results.add(user_story) |
- results.DidRunPage(user_story, discard_run=discard_run) |
+ has_existing_exception = sys.exc_info() is not None |
+ try: |
+ if state: |
+ _CheckThermalThrottling(state.platform) |
+ discard_run = (test.discard_first_result and |
+ user_story not in |
+ user_story_with_discarded_first_results) |
+ if discard_run: |
+ user_story_with_discarded_first_results.add(user_story) |
+ results.DidRunPage(user_story, discard_run=discard_run) |
+ except Exception: |
+ if not has_existing_exception: |
+ raise |
+ # Print current exception and propagate existing exception. |
+ exception_formatter.PrintFormattedException( |
+ msg='Exception from result processing:') |
if max_failures is not None and len(results.failures) > max_failures: |
logging.error('Too many failures. Aborting.') |
test.RequestExit() |
finally: |
if state: |
- state.TearDownState(results) |
+ has_existing_exception = sys.exc_info() is not None |
+ try: |
+ state.TearDownState(results) |
+ except Exception: |
+ if not has_existing_exception: |
+ raise |
+ # Print current exception and propagate existing exception. |
+ exception_formatter.PrintFormattedException( |
+ msg='Exception from TearDownState:') |
+ |
def _ShuffleAndFilterUserStorySet(user_story_set, finder_options): |
if finder_options.pageset_shuffle_order_file: |