1 # Copyright 2015 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.
7 from telemetry
import benchmark
as benchmark_module
8 from telemetry
.core
import exceptions
9 from telemetry
.page
import page
as page_module
10 from telemetry
.page
import page_test
11 from telemetry
.page
import shared_page_state
12 from telemetry
.value
import skip
14 import exception_formatter
15 import gpu_test_expectations
17 """Base classes for all GPU tests in this directory. Implements
18 support for per-page test expectations."""
20 def _PageOperationWrapper(page
, tab
, expectations
,
21 show_expected_failure
, inner_func
,
23 """Wraps an operation to be done against the page. If an error has
24 occurred in an earlier step, skips this entirely."""
29 expectation
= expectations
.GetExpectationForPage(tab
.browser
, page
)
30 if expectation
== 'skip':
32 'Skip expectations should have been handled at a higher level')
37 if expectation
== 'pass':
39 elif expectation
== 'fail':
40 msg
= 'Expected exception while running %s' % page
.display_name
41 exception_formatter
.PrintFormattedException(msg
=msg
)
42 elif expectation
== 'flaky':
43 # Retries are handled in RunStoryWithRetries, below.
47 'Unknown expectation %s while handling exception for %s' %
48 (expectation
, page
.display_name
))
51 if show_expected_failure
and expectation
== 'fail':
53 '%s was expected to fail, but passed.\n', page
.display_name
)
56 class TestBase(benchmark_module
.Benchmark
):
57 def __init__(self
, max_failures
=None):
58 super(TestBase
, self
).__init
__(max_failures
=max_failures
)
59 self
._cached
_expectations
= None
61 def GetExpectations(self
):
62 """Returns the expectations that apply to this test."""
63 if not self
._cached
_expectations
:
64 self
._cached
_expectations
= self
._CreateExpectations
()
65 if not isinstance(self
._cached
_expectations
,
66 gpu_test_expectations
.GpuTestExpectations
):
67 raise Exception('gpu_test_base requires use of GpuTestExpectations')
68 return self
._cached
_expectations
70 def _CreateExpectations(self
):
71 # By default, creates an empty GpuTestExpectations object. Override
72 # this in subclasses to set up test-specific expectations. Must
73 # return an instance of GpuTestExpectations or a subclass.
75 # Do not call this directly. Call GetExpectations where necessary.
76 return gpu_test_expectations
.GpuTestExpectations()
79 class ValidatorBase(page_test
.PageTest
):
81 needs_browser_restart_after_each_page
=False,
82 clear_cache_before_each_run
=False):
83 super(ValidatorBase
, self
).__init
__(
84 needs_browser_restart_after_each_page
=\
85 needs_browser_restart_after_each_page
,
86 clear_cache_before_each_run
=clear_cache_before_each_run
)
88 def WillNavigateToPage(self
, page
, tab
):
89 """Does operations before the page is navigated. Do not override this
90 method. Override WillNavigateToPageInner, below."""
91 _PageOperationWrapper(
92 page
, tab
, page
.GetExpectations(), False,
93 lambda: self
.WillNavigateToPageInner(page
, tab
))
95 def DidNavigateToPage(self
, page
, tab
):
96 """Does operations right after the page is navigated and after all
97 waiting for completion has occurred. Do not override this method.
98 Override DidNavigateToPageInner, below."""
99 _PageOperationWrapper(
100 page
, tab
, page
.GetExpectations(), False,
101 lambda: self
.DidNavigateToPageInner(page
, tab
))
103 def ValidateAndMeasurePage(self
, page
, tab
, results
):
104 """Validates and measures the page, taking into account test
105 expectations. Do not override this method. Override
106 ValidateAndMeasurePageInner, below."""
107 _PageOperationWrapper(
108 page
, tab
, page
.GetExpectations(), True,
109 lambda: self
.ValidateAndMeasurePageInner(page
, tab
, results
),
112 def WillNavigateToPageInner(self
, page
, tab
):
115 def DidNavigateToPageInner(self
, page
, tab
):
118 def ValidateAndMeasurePageInner(self
, page
, tab
, results
):
122 # NOTE: if you change this logic you must change the logic in
123 # FakeGpuSharedPageState (gpu_test_base_unittest.py) as well.
124 def _CanRunOnBrowser(browser_info
, page
):
125 expectations
= page
.GetExpectations()
126 return expectations
.GetExpectationForPage(
127 browser_info
.browser
, page
) != 'skip'
129 def RunStoryWithRetries(cls
, shared_page_state
, results
):
130 page
= shared_page_state
.current_page
132 super(cls
, shared_page_state
).RunStory(results
)
134 tab
= shared_page_state
.current_tab
135 num_retries
= page
.GetExpectations().GetFlakyRetriesForPage(
137 if page
.HadError() and num_retries
:
138 # Re-run the test up to |num_retries| times.
140 for ii
in xrange(0, num_retries
):
141 print 'FLAKY TEST FAILURE, retrying: ' + page
.display_name
143 super(cls
, shared_page_state
).RunStory(results
)
146 # Squelch any exceptions from any but the last retry.
147 if ii
== num_retries
- 1:
150 # Clear the error state in case we have to retry.
153 # Re-raise the exception.
156 # Clear the error state of the page at this point so that if
157 # --page-repeat or --pageset-repeat are used, the subsequent
158 # iterations don't turn into no-ops.
161 class GpuSharedPageState(shared_page_state
.SharedPageState
):
162 def CanRunOnBrowser(self
, browser_info
, page
):
163 return _CanRunOnBrowser(browser_info
, page
)
165 # NOTE: if you change this logic you must change the logic in
166 # FakeGpuSharedPageState (gpu_test_base_unittest.py) as well.
167 def RunStory(self
, results
):
168 RunStoryWithRetries(GpuSharedPageState
, self
, results
)
171 # TODO(kbr): re-evaluate the need for this SharedPageState
172 # subclass. It's only used by the WebGL conformance suite.
173 class DesktopGpuSharedPageState(
174 shared_page_state
.SharedDesktopPageState
):
175 def CanRunOnBrowser(self
, browser_info
, page
):
176 return _CanRunOnBrowser(browser_info
, page
)
178 # Note: if you change this logic you must change the logic in
179 # FakeGpuSharedPageState (gpu_test_base_unittest.py) as well.
180 def RunStory(self
, results
):
181 RunStoryWithRetries(DesktopGpuSharedPageState
, self
, results
)
184 class PageBase(page_module
.Page
):
185 # The convention is that pages subclassing this class must be
186 # configured with the test expectations.
187 def __init__(self
, url
, page_set
=None, base_dir
=None, name
='',
188 shared_page_state_class
=GpuSharedPageState
,
189 make_javascript_deterministic
=True,
191 super(PageBase
, self
).__init
__(
192 url
=url
, page_set
=page_set
, base_dir
=base_dir
, name
=name
,
193 shared_page_state_class
=shared_page_state_class
,
194 make_javascript_deterministic
=make_javascript_deterministic
)
195 # Disable automatic garbage collection to reduce the test's cycle time.
196 self
._collect
_garbage
_before
_run
= False
198 # TODO(kbr): this is fragile -- if someone changes the
199 # shared_page_state_class to something that doesn't handle skip
200 # expectations, then they'll hit the exception in
201 # _PageOperationWrapper, above. Need to rethink.
202 self
._expectations
= expectations
203 self
._had
_error
= False
204 self
._cached
_action
_runner
= None
206 def GetExpectations(self
):
207 return self
._expectations
210 return self
._had
_error
212 def SetHadError(self
):
213 self
._had
_error
= True
215 def ClearHadError(self
):
216 self
._had
_error
= False
219 def cached_action_runner(self
):
220 return self
._cached
_action
_runner
222 def RunNavigateSteps(self
, action_runner
):
223 """Runs navigation steps, taking into account test expectations.
224 Do not override this method. Override RunNavigateStepsInner, below."""
225 self
._cached
_action
_runner
= action_runner
227 self
.RunDefaultNavigateSteps(action_runner
)
228 self
.RunNavigateStepsInner(action_runner
)
229 _PageOperationWrapper(self
, action_runner
.tab
, self
.GetExpectations(),
232 def RunDefaultNavigateSteps(self
, action_runner
):
233 """Runs the default set of navigation steps inherited from page.Page."""
234 super(PageBase
, self
).RunNavigateSteps(action_runner
)
236 def RunNavigateStepsInner(self
, action_runner
):
239 def RunPageInteractions(self
, action_runner
):
240 """Runs page interactions, taking into account test expectations. Do not
241 override this method. Override RunPageInteractionsInner, below."""
243 super(PageBase
, self
).RunPageInteractions(action_runner
)
244 self
.RunPageInteractionsInner(action_runner
)
245 _PageOperationWrapper(self
, action_runner
.tab
, self
.GetExpectations(),
248 def RunPageInteractionsInner(self
, action_runner
):