1# Copyright 2014 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. 4 5from functools import wraps 6import logging 7import os 8import sys 9import types 10import unittest 11 12from telemetry.internal.browser import browser_finder 13from telemetry.internal.util import path 14from telemetry.testing import options_for_unittests 15 16 17class _MetaBrowserTestCase(type): 18 """Metaclass for BrowserTestCase. 19 20 The metaclass wraps all test* methods of all subclasses of BrowserTestCase to 21 print browser standard output and log upon failure. 22 """ 23 24 def __new__(mcs, name, bases, dct): 25 new_dct = {} 26 for attributeName, attribute in dct.iteritems(): 27 if (isinstance(attribute, types.FunctionType) and 28 attributeName.startswith('test')): 29 attribute = mcs._PrintBrowserStandardOutputAndLogOnFailure(attribute) 30 new_dct[attributeName] = attribute 31 return type.__new__(mcs, name, bases, new_dct) 32 33 @staticmethod 34 def _PrintBrowserStandardOutputAndLogOnFailure(method): 35 @wraps(method) 36 def WrappedMethod(self): 37 try: # pylint: disable=broad-except 38 method(self) 39 except Exception: 40 exc_info = sys.exc_info() 41 42 if self._browser: 43 self._browser.DumpStateUponFailure() 44 else: 45 logging.warning('Cannot dump browser state: No browser.') 46 47 # Re-raise the original exception. Note that we can't just use 'raise' 48 # without any arguments because an exception might have been thrown when 49 # dumping the state of the browser. 50 raise exc_info[0], exc_info[1], exc_info[2] 51 return WrappedMethod 52 53 54class BrowserTestCase(unittest.TestCase): 55 __metaclass__ = _MetaBrowserTestCase 56 _possible_browser = None 57 _platform = None 58 _browser = None 59 _device = None 60 61 def setUp(self): 62 if self._browser: 63 self._browser.CleanupUnsymbolizedMinidumps() 64 65 def tearDown(self): 66 if self._browser: 67 self._browser.CleanupUnsymbolizedMinidumps(fatal=True) 68 69 @classmethod 70 def setUpClass(cls): 71 try: 72 options = options_for_unittests.GetCopy() 73 cls.CustomizeBrowserOptions(options.browser_options) 74 cls._possible_browser = browser_finder.FindBrowser(options) 75 if not cls._possible_browser: 76 raise Exception('No browser found, cannot continue test.') 77 cls._platform = cls._possible_browser.platform 78 cls._platform.network_controller.Open() 79 cls._possible_browser.SetUpEnvironment(options.browser_options) 80 cls._browser = cls._possible_browser.Create() 81 cls._device = options.remote_platform_options.device 82 except: 83 # Try to tear down the class upon any errors during set up. 84 cls.tearDownClass() 85 raise 86 87 @classmethod 88 def tearDownClass(cls): 89 cls._device = None 90 if cls._browser is not None: 91 cls._browser.Close() 92 cls._browser = None 93 if cls._possible_browser is not None: 94 cls._possible_browser.CleanUpEnvironment() 95 cls._possible_browser = None 96 if cls._platform is not None: 97 cls._platform.StopAllLocalServers() 98 cls._platform.network_controller.Close() 99 cls._platform = None 100 101 @classmethod 102 def CustomizeBrowserOptions(cls, options): 103 """Override to add test-specific options to the BrowserOptions object""" 104 pass 105 106 @classmethod 107 def UrlOfUnittestFile(cls, filename, handler_class=None): 108 cls._platform.SetHTTPServerDirectories(path.GetUnittestDataDir(), 109 handler_class) 110 file_path = os.path.join(path.GetUnittestDataDir(), filename) 111 return cls._platform.http_server.UrlOf(file_path) 112