class TestXpathBrowser(unittest.TestCase): def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self._level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self._level_mngr.get_xpathbrowser(name=__name__) def tearDown(self): # Make sure we quit those webdrivers created in this specific level of life self._level_mngr.exit_level() def test_select(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath('//div') # Xpath must be present, but no inner element may be returned self.browser.select_xsingle('//div') # Xpath must be present and at least 1 element must be present def test_extract(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath('//div') # Xpath must be present, but no inner element may be returned self.browser.extract_xsingle('//div') # Xpath must be present and at least 1 element must be present def get_local_page(self, file_name): # Auxiliary method root_dir = os.path.abspath(os.path.dirname(__file__)) url = 'file://' + os.path.join(root_dir, 'html', file_name) self.browser.get_url(url)
def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self.__level_mngr = WebdriverManager().enter_level( level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self.__level_mngr.get_xpathbrowser(name=__name__)
class XpathShell(object): def __init__(self, logger=None): self.log = logger or Logger('Xpath Shell') def get(self, url): u = urlparse.urlparse(url) if not u.scheme: u = ('http', u.netloc, u.path, u.params, u.query, u.fragment) url = urlparse.urlunparse(u) self.browser.get_url(url) self.log.i('Current url: %r' % self.browser.current_url()) def run_shell(self, url=None): self.level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE) browser = self.browser = self.level_mngr.get_xpathbrowser(name='Browser') #Aliases #TODO: add ipython extension ex = extract = browser.extract_xpath exs = xsingle = browser.extract_xsingle get = self.get def reset_browser(): self.level_mngr.exit_level() self.level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE) if url: self.get(url) print('Available objects/commands %s' % sorted(locals())) IpythonEmbedder().embed() self.level_mngr.exit_level() WebdriverManager().stop_display()
class WebUnitTestBase(unittest.TestCase): def _path_to_url(self, path): return "file://" + path def get_local_page(self, path): self.browser.get_url(self._path_to_url(path)) @contextmanager def create_html(self, name, body, **kwargs): templ = """ <!DOCTYPE html> <html> <head> hotexamples_com <title>{name}</title> </head> <body> {body} </body> </html> """ jquery = "" kwargs.update(locals()) html = templ.format(**kwargs) if not self._tempdir: self._tempdir = tempfile.mkdtemp(prefix="smoothtest") path = os.path.join(self._tempdir, name + ".html") # Create html page in temporary dir with open(path, "w") as fh: fh.write(html) try: yield path except: raise finally: os.remove(path) def setUp(self): self.__level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) webdriver = self.__level_mngr.acquire_driver() logger = Logger(__name__) self.browser = XpathBrowser("", webdriver, logger, settings={}) # Temp dir to save pages self._tempdir = None def tearDown(self): self.__level_mngr.exit_level() if self._tempdir: shutil.rmtree(self._tempdir, ignore_errors=True) self._tempdir = None
class WebUnitTestBase(unittest.TestCase): def _get_local_html_path(self, name): return os.path.join(os.path.dirname(__file__), 'html', name) def _local_path_to_url(self, path): return 'file://' + path def get_local_page(self, path): self.browser.get_url(self._local_path_to_url(path)) @contextmanager def create_html(self, name, body, jquery=True, **kwargs): templ = ''' <!DOCTYPE html> <html> <head> hotexamples_com <title>{name}</title> </head> <body> {body} </body> </html> ''' if jquery: jquery = '' else: jquery = '' kwargs.update(locals()) html = templ.format(**kwargs) path = self._get_local_html_path(name + '.html') with open(path, 'w') as fh: fh.write(html) try: yield path except: raise finally: os.remove(path) def setUp(self): self.__level_mngr = WebdriverManager().enter_level( level=SINGLE_TEST_LIFE) webdriver = self.__level_mngr.acquire_driver() logger = Logger(__name__) self.browser = XpathBrowser('', webdriver, logger, settings={}) def tearDown(self): self.__level_mngr.exit_level()
class TestXpathBrowser(unittest.TestCase): def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self.__level_mngr = WebdriverManager().enter_level( level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self.__level_mngr.get_xpathbrowser(name=__name__) # Line above is equivalent to doing: # from smoothtest.Logger import Logger # from smoothtest.webunittest.XpathBrowser import XpathBrowser # # Once we make sure there is a webdriver available, we acquire it # # and block usage from other possible users # webdriver = self.__level_mngr.acquire_driver() # # Initialize the XpathBrowser class # logger = Logger(__name__) # self.browser = XpathBrowser('', webdriver, logger, settings={}) def tearDown(self): # Make sure we quit those webdrivers created in this specific level of life self.__level_mngr.exit_level() def test_select(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath( '//div' ) # Xpath must be present, but no inner element may be returned self.browser.select_xsingle( '//div' ) # Xpath must be present and at least 1 element must be present def test_extract(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath( '//div' ) # Xpath must be present, but no inner element may be returned self.browser.extract_xsingle( '//div' ) # Xpath must be present and at least 1 element must be present def get_local_page(self, file_name): # Auxiliary method root_dir = os.path.abspath(os.path.dirname(__file__)) url = 'file://' + os.path.join(root_dir, 'html', file_name) self.browser.get_url(url)
def __init__(self): ''' Initialize attributes ''' self._timeout = 1 self._ishell = None # Ipython Shell instance self.test_config = { } # Configuration parameters sent for each test round self._slave = None # Slave instance (configures how tests are ran) self._child_pids = [ ] # Store pids of children, in case we need to kill them self._wdriver_mngr = WebdriverManager( ) # common WebdriverManager instance self._browser_name = None # Current selected browser name self._level_mngr = None # WebdriverLevelManager for each time we enter/leave a "webdriver life level"
class TestChat(unittest.TestCase): @classmethod def setUpClass(cls): # It will initialize the webdriver if no webdriver is present from upper levels # Since we don't want to initialize a webdriver for each single test # we create the webdriver one level upper SINGLE_TEST_LIFE cls.cls_level_mngr = WebdriverManager().enter_level(level=TEST_ROUND_LIFE) @classmethod def tearDownClass(cls): cls.cls_level_mngr.exit_level() def setUp(self): # The webdriver is already initialized on previous level # We simply manage it's context with this new _level_mngr self._level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Lock webdriver and build XpathBrowser API self.browser = self._level_mngr.get_xpathbrowser(name=__name__) self.browser.set_base_url(base_url) def tearDown(self): # Release webdriver, we are not longer using it. self._level_mngr.exit_level() def test_loaded(self): b = self.browser b.get_page('/') # Make sure there is at least 1 element b.select_xsingle(".//*[@id='input_area']") def test_send_msg(self): browser1 = self.browser path = '/' with WebdriverManager().enter_level(level=SINGLE_TEST_LIFE, name='Browser2') \ as browser2: browser1.get_page(path) browser2.set_base_url(base_url) browser2.get_page(path) username = '******' message = 'my message' browser1.fill_input(".//*[@id='username']", username) browser1.fill_input(".//*[@id='message']", message) browser1.click(".//*[@id='input_area']/button") msgs_xpath = ".//*[@id='chat']/div" msg_recv = browser1.extract_xpath(msgs_xpath)[-1] self.assertEqual(msg_recv, '%s: %s' % (username, message)) msg_recv2 = browser2.extract_xpath(msgs_xpath)[-1] self.assertEqual(msg_recv, msg_recv2)
def setUpClass(cls): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels cls._level_mngr = WebdriverManager().enter_level(level=TEST_ROUND_LIFE) # Get Xpath browser cls.browser = cls._level_mngr.get_xpathbrowser(name=__name__) cls.browser.set_base_url(base_url)
def smoke_test_module(): from smoothtest.webunittest.WebdriverManager import WebdriverManager mngr = WebdriverManager() # mngr.setup_display() # webdriver = mngr.new_webdriver() u = u'https://www.google.cl/?gfe_rd=cr&ei=ix0kVfH8M9PgwASPoIFo&gws_rd=ssl' print WebdriverUtils.Url(u).get_path_and_on()
def setUp(self): # The webdriver is already initialized on previous level # We simply manage it's context with this new _level_mngr self._level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Lock webdriver and build XpathBrowser API self.browser = self._level_mngr.get_xpathbrowser(name=__name__) self.browser.set_base_url(base_url)
def setUp(self): self.__level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) webdriver = self.__level_mngr.acquire_driver() logger = Logger(__name__) self.browser = XpathBrowser("", webdriver, logger, settings={}) # Temp dir to save pages self._tempdir = None
def test(self, test_paths, argv=[], smoke=False): ''' :param test_paths: iterable like ['package.module.test_class.test_method', ...] ''' results = TestResults() if smoke or not test_paths: self.log.i('Ignoring %r \n (smoke mode or no tests found)' % list(test_paths)) return results level_mngr = WebdriverManager().enter_level(level=TEST_ROUND_LIFE) for tpath in test_paths: class_ = self._import_test(tpath) if isinstance(class_, TestException): results.append_result(tpath, class_) else: result = self._run_test(tpath, argv, class_) results.append_result(tpath, result) level_mngr.exit_level() return results
class SearchEnginesDemo(unittest.TestCase): def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self._level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self._level_mngr.get_xpathbrowser(name=__name__) def tearDown(self): # Make sure we quit those webdrivers created in this specific level of life self._level_mngr.exit_level() def test_duckduckgo(self): # Load a local page for the demo self.browser.get_url('https://duckduckgo.com/') # Type smoothtest and press enter self.browser.fill(".//*[@id='search_form_input_homepage']", 'smoothtest\n') result_link = './/a[@title="smoothtest "]' # Wait for the result to be available self.browser.wait_condition(lambda brw: brw.select_xpath(result_link)) # Click on result self.browser.click(result_link) # First result should point to github expected_url = 'https://github.com/joaduo/smoothtest' wait_url = lambda brw: brw.current_url() == expected_url # Make sure we end up in the right url self.assertTrue(self.browser.wait_condition(wait_url)) def test_google(self): # go to google self.browser.get_url('https://www.google.com/') # search for smoothtest and press enter self.browser.fill(".//*[@id='lst-ib']", 'smoothtest\n') first_result = './/a[contains(text(),"smoothtest 0.1.3")]' # Wait for first result self.browser.wait_condition(lambda brw: brw.select_xpath(first_result)) # Click first result self.browser.click(first_result) # Make sure we went to pypi wait_pypi_url = lambda brw: brw.current_url() == 'https://pypi.python.org/pypi/smoothtest/0.1.3' self.assertTrue(self.browser.wait_condition(wait_pypi_url))
def __init__(self): ''' Initialize attributes ''' self._timeout = 1 self._ishell = None # Ipython Shell instance self.test_config = {} # Configuration parameters sent for each test round self._slave = None # Slave instance (configures how tests are ran) self._child_pids = [] # Store pids of children, in case we need to kill them self._wdriver_mngr = WebdriverManager() # common WebdriverManager instance self._browser_name = None # Current selected browser name self._level_mngr = None # WebdriverLevelManager for each time we enter/leave a "webdriver life level"
def smoke_test_module(): from smoothtest.webunittest.WebdriverManager import WebdriverManager from smoothtest.settings.default import SINGLE_TEST_LIFE mngr = WebdriverManager() mngr.set_browser('Firefox') lvl = mngr.enter_level(level=SINGLE_TEST_LIFE) class ExampleTest(object): def test_something(self): raise LookupError('Example Exception') test = ExampleTest() browser = lvl.get_xpathbrowser(name='test') get_browser = lambda : browser dec = ScreenshotDecorator(get_browser, test) dec._decorate_exc_sshot() lvl.get_locked_driver().get('http://www.example.com') try: test.test_something() except Exception as e: pass #print e lvl.exit_level()
class TestXpathBrowser(unittest.TestCase): def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self.__level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self.__level_mngr.get_xpathbrowser(name=__name__) # Line above is equivalent to doing: # from smoothtest.Logger import Logger # from smoothtest.webunittest.XpathBrowser import XpathBrowser # # Once we make sure there is a webdriver available, we acquire it # # and block usage from other possible users # webdriver = self.__level_mngr.acquire_driver() # # Initialize the XpathBrowser class # logger = Logger(__name__) # self.browser = XpathBrowser('', webdriver, logger, settings={}) def tearDown(self): # Make sure we quit those webdrivers created in this specific level of life self.__level_mngr.exit_level() def test_select(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath('//div') # Xpath must be present, but no inner element may be returned self.browser.select_xsingle('//div') # Xpath must be present and at least 1 element must be present def test_extract(self): # Load a local page for the demo self.get_local_page('xpath_browser_demo.html') # Do 2 type of selection self.browser.select_xpath('//div') # Xpath must be present, but no inner element may be returned self.browser.extract_xsingle('//div') # Xpath must be present and at least 1 element must be present def get_local_page(self, file_name): # Auxiliary method root_dir = os.path.abspath(os.path.dirname(__file__)) url = 'file://' + os.path.join(root_dir, 'html', file_name) self.browser.get_url(url)
def smoke_test_module(): from smoothtest.webunittest.WebdriverManager import WebdriverManager from smoothtest.settings.default import SINGLE_TEST_LIFE mngr = WebdriverManager() mngr.set_browser('Firefox') lvl = mngr.enter_level(level=SINGLE_TEST_LIFE) class ExampleTest(object): def test_something(self): raise LookupError('Example Exception') test = ExampleTest() browser = lvl.get_xpathbrowser(name='test') get_browser = lambda: browser dec = ScreenshotDecorator(get_browser, test) dec._decorate_exc_sshot() lvl.get_locked_driver().get('http://www.example.com') try: test.test_something() except Exception as e: pass #print e lvl.exit_level()
def run_shell(self, url=None): self.level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE) browser = self.browser = self.level_mngr.get_xpathbrowser(name='Browser') #Aliases #TODO: add ipython extension ex = extract = browser.extract_xpath exs = xsingle = browser.extract_xsingle get = self.get def reset_browser(): self.level_mngr.exit_level() self.level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE) if url: self.get(url) print('Available objects/commands %s' % sorted(locals())) IpythonEmbedder().embed() self.level_mngr.exit_level() WebdriverManager().stop_display()
def run_shell(self, url=None): level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE) browser = self.browser = level_mngr.get_xpathbrowser(name='Browser') #Aliases #TODO: add ipython extension ex = extract = browser.extract_xpath exs = xsingle = browser.extract_xsingle get = self.get if url: self.get(url) IpythonEmbedder().embed() level_mngr.exit_level() WebdriverManager().stop_display()
def reset_browser(): self.level_mngr.exit_level() self.level_mngr = WebdriverManager().enter_level(level=PROCESS_LIFE)
def stop_display(self): ''' Stop display if there is a virtual screen running ''' WebdriverManager().stop_display()
class Main(ParentBase): ''' This class contains the "main loop" logic of the autotest command It will create 2 forked subprocess as: Main Process (this one) Master Subprocess (Child) TestRunner Subprocess (Grand Child) Roles are as: Main: where the CLI loop is done, sending commands to Master. Master: where file watching happens; events from Main and TestRunner are integrated decides whether to: trigger tests, kill TestRunner and recreate it. TestRunner: where tests are loaded and ran, test results are sent back to Master. ''' def __init__(self): ''' Initialize attributes ''' self._timeout = 1 self._ishell = None # Ipython Shell instance self.test_config = { } # Configuration parameters sent for each test round self._slave = None # Slave instance (configures how tests are ran) self._child_pids = [ ] # Store pids of children, in case we need to kill them self._wdriver_mngr = WebdriverManager( ) # common WebdriverManager instance self._browser_name = None # Current selected browser name self._level_mngr = None # WebdriverLevelManager for each time we enter/leave a "webdriver life level" def run(self, test_config, embed_ipython=False, block=False): ''' Runs the main CLI loop. If ipython is not present it will fallback to gdb as CLI. :param test_config: initial configuration parameters :param embed_ipython: if True, it will embed a interactive shell. :param block: block waiting for events (in case no shell was enabled) ''' self.log.set_pre_post(pre='Autotest CLI') self.test_config = test_config self.create_child() if embed_ipython: from .ipython_extension import load_extension def extension(ipython): return load_extension(ipython, self) self._ishell = IpythonEmbedder().embed(extension) self.kill_child() self.end_main() self._wdriver_mngr.stop_display() raise SystemExit(0) elif block: self.log.i(self.recv()) def create_child(self): ''' Create Master role subprocess ''' slave = self._build_slave() def callback(conn): if self._ishell: self._ishell.exit_now = True sys.stdin.close() master = Master(conn, slave) poll = master.io_loop(self.test_config) while True: poll.next() self.start_subprocess(callback, pre='Master') slave_pid = self.call_remote(Master.get_subprocess_pid) self._child_pids.append(('slave_pid', slave_pid)) self._child_pids.append(('master_pid', self.get_subprocess_pid())) def _build_slave(self): # Build the Slave class instance (used to control how tests are ran) if not self._slave: # Release no longer used webdriver if self._level_mngr: self._level_mngr.release_driver() # Quit those drivers not responding self._wdriver_mngr.quit_all_failed_webdrivers() self._wdriver_mngr.set_browser(self._get_browser_name()) # Enter the level again self._level_mngr = self._wdriver_mngr.enter_level( level=PROCESS_LIFE) self._slave = Slave(TestRunner) return self._slave def _set_browser_name(self, browser): # Set the default browser to use from now on self._browser_name = browser or self._browser_name def _get_browser_name(self): # Get the name of the current browser in use return self._browser_name or self.global_settings.get( 'webdriver_browser') def reset(self): ''' Reset as if we were from a fresh start. ''' self.end_main() self._wdriver_mngr.quit_all_failed_webdrivers() self.kill_child() self.create_child() def new_browser(self, browser=None): ''' Select a new current browser to run tests with. (will create if missing else reuse) :param browser: browser's name string. Eg:'Firefox', 'Chrome', 'PhantomJS' ''' self._set_browser_name(browser) self.kill_child() self.create_child() def send_test(self, **test_config): ''' Send tests config parameters to the Master process. (which in turn will send to TestRunner) ''' if self._healthy_webdriver(): self.send_recv('new_test', **test_config) self.test_config = test_config def test(self): ''' Send parcial reload testing command. Means testing without recreating TestRunner subprocess ''' if self._healthy_webdriver(): cmd = 'partial_callback' ans = self.send_recv(cmd) self.log.e(ans.error) return ans def _healthy_webdriver(self): # Check if used webdrivers are in healthy status if self._wdriver_mngr.quit_all_failed_webdrivers(): self.log.w('Webdriver failed. Restarting subprocesses...') # Restart browser if needed self.new_browser() return False return True def send(self, cmd, *args, **kwargs): ''' Send arbitrary commands to the Master subprocess. Also make sure no remaining incoming data is in the pipe buffer before sending. :param cmd: method name of Master class :param args: variable args matching the signature of the remote method :param kwargs: variable keyword args matching the signature of the remote method ''' while self.poll(): self.log.i('Remaining in buffer: %r' % self.recv()) return super(Main, self).send(cmd, *args, **kwargs) def kill_child(self): ''' Send a kill command to the Master subprocess. If unable to gently die, we force killing Master subprocess. ''' answer = self.kill(block=True, timeout=3) self._force_kill(self._child_pids) self._slave = None self._child_pids = [] return answer def _force_kill(self, child_pids): ''' Fallback mechanism that sends SIGKILL signal if any subprocess is still up. :param child_pids: iterable of subprocesses pids ''' def process_running(pid): # Check For the existence of a unix pid. try: # Why not use signal.SIG_DFL ? (= 0) # Seems 0 will kill a process on Windows # http://stackoverflow.com/questions/568271/how-to-check-if-there-exists-a-process-with-a-given-pid os.kill(pid, 0) return True except OSError: return False for name, pid in child_pids: if process_running(pid): self.log.w('Pid (%r,%r) still up. Sending SIGKILL...' % (name, pid)) os.kill(pid, signal.SIGKILL) def end_main(self): ''' Function we call when leaving the main loop or when resetting the testing. ''' if self._level_mngr: self._level_mngr.exit_level() self._level_mngr = None def steal_xpathbrowser(self, browser): ''' Get an XpathBrowser instance bypassing any locking mechanism. (debugging purposes) :param browser: browser's name string ''' browser = self._wdriver_mngr.expand_browser_name(browser) webdrivers = self._wdriver_mngr.list_webdrivers(which='all') for wd, (brwsr, _) in webdrivers.iteritems(): if browser == brwsr: return XpathBrowser(None, wd)
class Main(ParentBase): ''' This class contains the "main loop" logic of the autotest command It will create 2 forked subprocess as: Main Process (this one) Master Subprocess (Child) TestRunner Subprocess (Grand Child) Roles are as: Main: where the CLI loop is done, sending commands to Master. Master: where file watching happens; events from Main and TestRunner are integrated decides whether to: trigger tests, kill TestRunner and recreate it. TestRunner: where tests are loaded and ran, test results are sent back to Master. ''' def __init__(self): ''' Initialize attributes ''' self._timeout = 1 self._ishell = None # Ipython Shell instance self.test_config = {} # Configuration parameters sent for each test round self._slave = None # Slave instance (configures how tests are ran) self._child_pids = [] # Store pids of children, in case we need to kill them self._wdriver_mngr = WebdriverManager() # common WebdriverManager instance self._browser_name = None # Current selected browser name self._level_mngr = None # WebdriverLevelManager for each time we enter/leave a "webdriver life level" def run(self, test_config, embed_ipython=False, block=False): ''' Runs the main CLI loop. If ipython is not present it will fallback to gdb as CLI. :param test_config: initial configuration parameters :param embed_ipython: if True, it will embed a interactive shell. :param block: block waiting for events (in case no shell was enabled) ''' self.log.set_pre_post(pre='Autotest CLI') self.test_config = test_config self.create_child() if embed_ipython: from .ipython_extension import load_extension def extension(ipython): return load_extension(ipython, self) self._ishell = IpythonEmbedder().embed(extension) self.kill_child() self.end_main() self._wdriver_mngr.stop_display() raise SystemExit(0) elif block: self.log.i(self.recv()) def create_child(self): ''' Create Master role subprocess ''' slave = self._build_slave() def callback(conn): if self._ishell: self._ishell.exit_now = True sys.stdin.close() master = Master(conn, slave) poll = master.io_loop(self.test_config) while True: poll.next() self.start_subprocess(callback, pre='Master') slave_pid = self.call_remote(Master.get_subprocess_pid) self._child_pids.append(('slave_pid', slave_pid)) self._child_pids.append(('master_pid', self.get_subprocess_pid())) def _build_slave(self): # Build the Slave class instance (used to control how tests are ran) if not self._slave: # Release no longer used webdriver if self._level_mngr: self._level_mngr.release_driver() # Quit those drivers not responding self._wdriver_mngr.quit_all_failed_webdrivers() self._wdriver_mngr.set_browser(self._get_browser_name()) # Enter the level again self._level_mngr = self._wdriver_mngr.enter_level(level=PROCESS_LIFE) self._slave = Slave(TestRunner) return self._slave def _set_browser_name(self, browser): # Set the default browser to use from now on self._browser_name = browser or self._browser_name def _get_browser_name(self): # Get the name of the current browser in use return self._browser_name or self.global_settings.get('webdriver_browser') def reset(self): ''' Reset as if we were from a fresh start. ''' self.end_main() self._wdriver_mngr.quit_all_failed_webdrivers() self.kill_child() self.create_child() def new_browser(self, browser=None): ''' Select a new current browser to run tests with. (will create if missing else reuse) :param browser: browser's name string. Eg:'Firefox', 'Chrome', 'PhantomJS' ''' self._set_browser_name(browser) self.kill_child() self.create_child() def send_test(self, **test_config): ''' Send tests config parameters to the Master process. (which in turn will send to TestRunner) ''' if self._healthy_webdriver(): self.send_recv('new_test', **test_config) self.test_config = test_config def test(self): ''' Send parcial reload testing command. Means testing without recreating TestRunner subprocess ''' if self._healthy_webdriver(): cmd = 'partial_callback' ans = self.send_recv(cmd) self.log.e(ans.error) return ans def _healthy_webdriver(self): # Check if used webdrivers are in healthy status if self._wdriver_mngr.quit_all_failed_webdrivers(): self.log.w('Webdriver failed. Restarting subprocesses...') # Restart browser if needed self.new_browser() return False return True def send(self, cmd, *args, **kwargs): ''' Send arbitrary commands to the Master subprocess. Also make sure no remaining incoming data is in the pipe buffer before sending. :param cmd: method name of Master class :param args: variable args matching the signature of the remote method :param kwargs: variable keyword args matching the signature of the remote method ''' while self.poll(): self.log.i('Remaining in buffer: %r' % self.recv()) return super(Main, self).send(cmd, *args, **kwargs) def kill_child(self): ''' Send a kill command to the Master subprocess. If unable to gently die, we force killing Master subprocess. ''' answer = self.kill(block=True, timeout=3) self._force_kill(self._child_pids) self._slave = None self._child_pids = [] return answer def _force_kill(self, child_pids): ''' Fallback mechanism that sends SIGKILL signal if any subprocess is still up. :param child_pids: iterable of subprocesses pids ''' def process_running(pid): # Check For the existence of a unix pid. try: # Why not use signal.SIG_DFL ? (= 0) # Seems 0 will kill a process on Windows # http://stackoverflow.com/questions/568271/how-to-check-if-there-exists-a-process-with-a-given-pid os.kill(pid, 0) return True except OSError: return False for name, pid in child_pids: if process_running(pid): self.log.w('Pid (%r,%r) still up. Sending SIGKILL...' % (name, pid)) os.kill(pid, signal.SIGKILL) def end_main(self): ''' Function we call when leaving the main loop or when resetting the testing. ''' if self._level_mngr: self._level_mngr.exit_level() self._level_mngr = None def steal_xpathbrowser(self, browser): ''' Get an XpathBrowser instance bypassing any locking mechanism. (debugging purposes) :param browser: browser's name string ''' browser = self._wdriver_mngr.expand_browser_name(browser) webdrivers = self._wdriver_mngr.list_webdrivers(which='all') for wd, (brwsr, _) in webdrivers.iteritems(): if browser == brwsr: return XpathBrowser(None, wd)
def __init__(self): super(TestRunner, self).__init__() self._level_mngr = WebdriverManager().enter_level( level=TEST_RUNNER_LIFE)
class TestRunner(ChildBase, TestRunnerBase): ''' Responsabilities - Import the Test Class - Run test over all methods or specific methods - Report any errors ''' def __init__(self): super(TestRunner, self).__init__() self._level_mngr = WebdriverManager().enter_level( level=TEST_RUNNER_LIFE) def test(self, test_paths, argv=[], smoke=False): ''' :param test_paths: iterable like ['package.module.test_class.test_method', ...] ''' results = TestResults() if smoke or not test_paths: self.log.i('Ignoring %r \n (smoke mode or no tests found)' % list(test_paths)) return results level_mngr = WebdriverManager().enter_level(level=TEST_ROUND_LIFE) for tpath in test_paths: class_ = self._import_test(tpath) if isinstance(class_, TestException): results.append_result(tpath, class_) else: result = self._run_test(tpath, argv, class_) results.append_result(tpath, result) level_mngr.exit_level() return results def io_loop(self, conn, stdin=None, stdout=None, stderr=None): while True: self._dispatch_cmds(conn) def _receive_kill(self, *args, **kwargs): self._tear_down_process() self._level_mngr.exit_level() def _run_test(self, test_path, argv, class_): try: _, _, methstr = self._split_path(test_path) suite = unittest.TestSuite() suite.addTest(class_(methstr)) runner = unittest.TextTestRunner() self._setup_process(class_, test_path, argv) return runner.run(suite) except Exception as e: return self.reprex(e) def _split_path(self, test_path): return self.split_test_path(test_path, meth=True) def _import_test(self, test_path): modstr, clsstr, _ = self._split_path(test_path) try: module = importlib.import_module(modstr) module = reload(module) class_ = getattr(module, clsstr) return class_ except Exception as e: return self.reprex(e)
def setUp(self): # We need to enter "single test level" of life for each test # It will initialize the webdriver if no webdriver is present from upper levels self._level_mngr = WebdriverManager().enter_level(level=SINGLE_TEST_LIFE) # Get Xpath browser self.browser = self._level_mngr.get_xpathbrowser(name=__name__)
class TestRunner(ChildBase, TestRunnerBase): ''' Responsabilities - Import the Test Class - Run test over all methods or specific methods - Report any errors ''' def __init__(self): super(TestRunner, self).__init__() self._level_mngr = WebdriverManager().enter_level(level=TEST_RUNNER_LIFE) def test(self, test_paths, argv=[], smoke=False): ''' :param test_paths: iterable like ['package.module.test_class.test_method', ...] ''' results = TestResults() if smoke or not test_paths: self.log.i('Ignoring %r \n (smoke mode or no tests found)' % list(test_paths)) return results level_mngr = WebdriverManager().enter_level(level=TEST_ROUND_LIFE) for tpath in test_paths: class_ = self._import_test(tpath) if isinstance(class_, TestException): results.append_result(tpath, class_) else: result = self._run_test(tpath, argv, class_) results.append_result(tpath, result) level_mngr.exit_level() return results def io_loop(self, conn, stdin=None, stdout=None, stderr=None): while True: self._dispatch_cmds(conn) def _receive_kill(self, *args, **kwargs): self._tear_down_process() self._level_mngr.exit_level() def _run_test(self, test_path, argv, class_): try: _, _, methstr = self._split_path(test_path) suite = unittest.TestSuite() suite.addTest(class_(methstr)) runner = unittest.TextTestRunner() self._setup_process(class_, test_path, argv) return runner.run(suite) except Exception as e: return self.reprex(e) def _split_path(self, test_path): return self.split_test_path(test_path, meth=True) def _import_test(self, test_path): modstr, clsstr, _ = self._split_path(test_path) try: module = importlib.import_module(modstr) module = reload(module) class_ = getattr(module, clsstr) return class_ except Exception as e: return self.reprex(e)
def setUp(self): self.__level_mngr = WebdriverManager().enter_level( level=SINGLE_TEST_LIFE) webdriver = self.__level_mngr.acquire_driver() logger = Logger(__name__) self.browser = XpathBrowser('', webdriver, logger, settings={})
def __init__(self): super(TestRunner, self).__init__() self._level_mngr = WebdriverManager().enter_level(level=TEST_RUNNER_LIFE)