| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from functools import wraps |
| import logging |
| import os |
| import sys |
| import types |
| import unittest |
| |
| from telemetry.internal.browser import browser_finder |
| from telemetry.internal.util import path |
| from telemetry.testing import options_for_unittests |
| |
| current_browser_options = None |
| current_browser = None |
| |
| |
| class _MetaBrowserTestCase(type): |
| """Metaclass for BrowserTestCase. |
| |
| The metaclass wraps all test* methods of all subclasses of BrowserTestCase to |
| print browser standard output and log upon failure. |
| """ |
| |
| def __new__(mcs, name, bases, dct): |
| new_dct = {} |
| for attributeName, attribute in dct.iteritems(): |
| if (isinstance(attribute, types.FunctionType) and |
| attributeName.startswith('test')): |
| attribute = mcs._PrintBrowserStandardOutputAndLogOnFailure(attribute) |
| new_dct[attributeName] = attribute |
| return type.__new__(mcs, name, bases, new_dct) |
| |
| @staticmethod |
| def _PrintBrowserStandardOutputAndLogOnFailure(method): |
| @wraps(method) |
| def WrappedMethod(self): |
| try: # pylint: disable=broad-except |
| method(self) |
| except Exception: |
| exc_info = sys.exc_info() |
| |
| if self._browser: |
| self._browser.DumpStateUponFailure() |
| else: |
| logging.warning('Cannot dump browser state: No browser.') |
| |
| # Re-raise the original exception. Note that we can't just use 'raise' |
| # without any arguments because an exception might have been thrown when |
| # dumping the state of the browser. |
| raise exc_info[0], exc_info[1], exc_info[2] |
| return WrappedMethod |
| |
| |
| def teardown_browser(): |
| global current_browser |
| global current_browser_options |
| |
| if current_browser: |
| current_browser.Close() |
| current_browser.platform.network_controller.Close() |
| current_browser = None |
| current_browser_options = None |
| |
| |
| class BrowserTestCase(unittest.TestCase): |
| __metaclass__ = _MetaBrowserTestCase |
| |
| @classmethod |
| def setUpClass(cls): |
| cls._platform = None |
| global current_browser |
| global current_browser_options |
| |
| options = options_for_unittests.GetCopy() |
| |
| cls.CustomizeBrowserOptions(options.browser_options) |
| if not current_browser or (current_browser_options != |
| options.browser_options): |
| if current_browser: |
| teardown_browser() |
| |
| browser_to_create = browser_finder.FindBrowser(options) |
| if not browser_to_create: |
| raise Exception('No browser found, cannot continue test.') |
| cls._platform = browser_to_create.platform |
| cls._platform.network_controller.InitializeIfNeeded() |
| |
| try: |
| current_browser = browser_to_create.Create(options) |
| current_browser_options = options.browser_options |
| except: |
| cls.tearDownClass() |
| raise |
| cls._browser = current_browser |
| cls._device = options.remote_platform_options.device |
| |
| @classmethod |
| def tearDownClass(cls): |
| if cls._platform: |
| cls._platform.StopAllLocalServers() |
| cls._platform.network_controller.Close() |
| |
| @classmethod |
| def CustomizeBrowserOptions(cls, options): |
| """Override to add test-specific options to the BrowserOptions object""" |
| pass |
| |
| @classmethod |
| def UrlOfUnittestFile(cls, filename): |
| cls._platform.SetHTTPServerDirectories(path.GetUnittestDataDir()) |
| file_path = os.path.join(path.GetUnittestDataDir(), filename) |
| return cls._platform.http_server.UrlOf(file_path) |