Index: telemetry/telemetry/internal/story_runner_unittest.py |
diff --git a/telemetry/telemetry/internal/story_runner_unittest.py b/telemetry/telemetry/internal/story_runner_unittest.py |
index da326424501b435e2a5b35240e6489bd6c1deaae..6e955b871327644dd3d2abb62ef18f0d8e6b8399 100644 |
--- a/telemetry/telemetry/internal/story_runner_unittest.py |
+++ b/telemetry/telemetry/internal/story_runner_unittest.py |
@@ -13,6 +13,8 @@ from telemetry import benchmark |
from telemetry.core import exceptions |
from telemetry.core import util |
from telemetry import decorators |
+from telemetry.internal.actions import page_action |
+from telemetry.internal.results import page_test_results |
from telemetry.internal.results import results_options |
from telemetry.internal import story_runner |
from telemetry.internal.util import exception_formatter as ex_formatter_module |
@@ -22,9 +24,11 @@ from telemetry import story as story_module |
from telemetry.testing import options_for_unittests |
from telemetry.testing import system_stub |
import mock |
+from telemetry.value import failure |
from telemetry.value import improvement_direction |
from telemetry.value import list_of_scalar_values |
from telemetry.value import scalar |
+from telemetry.value import skip |
from telemetry.value import summary as summary_module |
from telemetry.web_perf import story_test |
from telemetry.web_perf import timeline_based_measurement |
@@ -72,6 +76,9 @@ class TestSharedState(story_module.SharedState): |
def TearDownState(self): |
pass |
+ def DumpStateUponFailure(self, story, results): |
+ pass |
+ |
class TestSharedPageState(TestSharedState): |
def RunStory(self, results): |
@@ -151,6 +158,22 @@ class TestOnlyException(Exception): |
pass |
+class FailureValueMatcher(object): |
+ |
+ def __init__(self, expected_exception_message): |
+ self._expected_exception_message = expected_exception_message |
+ |
+ def __eq__(self, other): |
+ return (isinstance(other, failure.FailureValue) and |
+ other.exc_info[1].message == self._expected_exception_message) |
+ |
+ |
+class SkipValueMatcher(object): |
+ |
+ def __eq__(self, other): |
+ return isinstance(other, skip.SkipValue) |
+ |
+ |
class StoryRunnerTest(unittest.TestCase): |
def setUp(self): |
@@ -507,6 +530,9 @@ class StoryRunnerTest(unittest.TestCase): |
unit_test_events.append('tear-down-state') |
raise DidRunTestError |
+ def DumpStateUponFailure(self, story, results): |
+ unit_test_events.append('dump-state') |
+ |
class Test(legacy_page_test.LegacyPageTest): |
def __init__(self, *args): |
@@ -530,7 +556,8 @@ class StoryRunnerTest(unittest.TestCase): |
with self.assertRaises(DidRunTestError): |
story_runner.Run( |
test, story_set, self.options, self.results) |
- self.assertEqual(['app-crash', 'tear-down-state'], unit_test_events) |
+ self.assertEqual(['app-crash', 'dump-state', 'tear-down-state'], |
+ unit_test_events) |
# The AppCrashException gets added as a failure. |
self.assertEquals(1, len(self.results.failures)) |
@@ -678,6 +705,9 @@ class StoryRunnerTest(unittest.TestCase): |
def TearDownState(self): |
pass |
+ def DumpStateUponFailure(self, story, results): |
+ pass |
+ |
class FailingStory(story_module.Story): |
def __init__(self): |
super(FailingStory, self).__init__( |
@@ -730,3 +760,221 @@ class StoryRunnerTest(unittest.TestCase): |
self._testMaxFailuresOptionIsRespectedAndOverridable( |
num_failing_stories=5, runner_max_failures=3, |
options_max_failures=1, expected_num_failures=2) |
+ |
+ def _CreateErrorProcessingMock(self, method_exceptions=None, |
+ legacy_test=False): |
+ if legacy_test: |
+ test_class = legacy_page_test.LegacyPageTest |
+ else: |
+ test_class = story_test.StoryTest |
+ |
+ root_mock = mock.NonCallableMock( |
+ story=mock.NonCallableMagicMock(story_module.Story), |
+ results=mock.NonCallableMagicMock(page_test_results.PageTestResults), |
+ test=mock.NonCallableMagicMock(test_class), |
+ state=mock.NonCallableMagicMock( |
+ story_module.SharedState, |
+ CanRunStory=mock.Mock(return_value=True))) |
+ |
+ if method_exceptions: |
+ root_mock.configure_mock(**{ |
+ path + '.side_effect': exception |
+ for path, exception in method_exceptions.iteritems()}) |
+ |
+ return root_mock |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_success(self): |
+ root_mock = self._CreateErrorProcessingMock() |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.test.Measure(root_mock.state.platform, root_mock.results), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_successLegacy(self): |
+ root_mock = self._CreateErrorProcessingMock(legacy_test=True) |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunPage(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryTimeout(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.WillRunStory': exceptions.TimeoutException('foo') |
+ }) |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryError(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.CanRunStory': exceptions.Error('foo') |
+ }) |
+ |
+ with self.assertRaisesRegexp(exceptions.Error, 'foo'): |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryUnsupportedAction(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.RunStory': page_action.PageActionNotSupported('foo') |
+ }) |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.results.AddValue(SkipValueMatcher()), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryUnhandlable(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'test.WillRunStory': Exception('foo') |
+ }) |
+ |
+ with self.assertRaisesRegexp(Exception, 'foo'): |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_finallyException(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.DidRunStory': Exception('bar') |
+ }) |
+ |
+ with self.assertRaisesRegexp(Exception, 'bar'): |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.test.Measure(root_mock.state.platform, root_mock.results), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryTimeout_finallyException(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.RunStory': exceptions.TimeoutException('foo'), |
+ 'state.DidRunStory': Exception('bar') |
+ }) |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryError_finallyException(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'state.WillRunStory': exceptions.Error('foo'), |
+ 'test.DidRunStory': Exception('bar') |
+ }) |
+ |
+ with self.assertRaisesRegexp(exceptions.Error, 'foo'): |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryUnsupportedAction_finallyException( |
+ self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'test.WillRunStory': page_action.PageActionNotSupported('foo'), |
+ 'state.DidRunStory': Exception('bar') |
+ }) |
+ |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.results.AddValue(SkipValueMatcher()), |
+ mock.call.state.DidRunStory(root_mock.results) |
+ ]) |
+ |
+ def testRunStoryAndProcessErrorIfNeeded_tryUnhandlable_finallyException(self): |
+ root_mock = self._CreateErrorProcessingMock(method_exceptions={ |
+ 'test.Measure': Exception('foo'), |
+ 'test.DidRunStory': Exception('bar') |
+ }) |
+ |
+ with self.assertRaisesRegexp(Exception, 'foo'): |
+ story_runner._RunStoryAndProcessErrorIfNeeded( |
+ root_mock.story, root_mock.results, root_mock.state, root_mock.test) |
+ |
+ self.assertEquals(root_mock.method_calls, [ |
+ mock.call.test.WillRunStory(root_mock.state.platform), |
+ mock.call.state.WillRunStory(root_mock.story), |
+ mock.call.state.CanRunStory(root_mock.story), |
+ mock.call.state.RunStory(root_mock.results), |
+ mock.call.test.Measure(root_mock.state.platform, root_mock.results), |
+ mock.call.state.DumpStateUponFailure(root_mock.story, root_mock.results), |
+ mock.call.results.AddValue(FailureValueMatcher('foo')), |
+ mock.call.state.DidRunStory(root_mock.results), |
+ mock.call.test.DidRunStory(root_mock.state.platform) |
+ ]) |