[Checkins] SVN: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/ Adding a new branch to work on:
Mathieu Le Marec - Pasquet
kiorky at cryptelium.net
Tue Apr 28 16:13:38 EDT 2009
Log message for revision 99565:
Adding a new branch to work on:
* proxy mode backport from collective.anonymousbrowser
* integration with mozrunner
* put in class the screenshot feature
* make some speed improvments on the firefox based class
Changed:
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/README.txt
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/buildout.cfg
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/setup.py
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/README.txt
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/authors.txt
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/firefox/
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/firefox/__init__.py
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/firefox/mozrepl.xpi
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.py
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.txt
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.py
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.txt
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/screen-shots.txt
U zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/tests.py
A zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/utils.py
-=-
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/README.txt
===================================================================
--- zc.testbrowser/trunk/README.txt 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/README.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -1,5 +1,5 @@
Overview
-========
+==========
The zc.testbrowser package provides web user agents (browsers) with
programmatic interfaces designed to be used for testing web applications,
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/buildout.cfg
===================================================================
--- zc.testbrowser/trunk/buildout.cfg 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/buildout.cfg 2009-04-28 20:13:37 UTC (rev 99565)
@@ -1,29 +1,32 @@
[buildout]
+extensions=buildout.minitagificator
develop = .
-parts = test interpreter
+parts =
+ test
+ interpreter
versions = versions
-index = http://download.zope.org/ppix/
[test]
recipe = zc.recipe.testrunner
defaults = ['-1', '--auto-color']
-eggs = zc.testbrowser
+eggs = zc.testbrowser [test]
[interpreter]
recipe = zc.recipe.egg
-eggs = zc.testbrowser
+eggs = zc.testbrowser [test]
interpreter = py
+scripts=ipython
[versions]
ClientForm = 0.2.7
mechanize = 0.1.7b
setuptools = 0.6c9
simplejson = 1.7.1
-zc.buildout = 1.1.1
zc.recipe.egg = 1.1.0
zc.recipe.testrunner = 1.1.0
zope.event = 3.4.0
zope.i18nmessageid = 3.4.0
zope.interface = 3.4.0
+zc.buildout=1.1.1
zope.schema = 3.3.0
zope.testing = 3.7.0
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/setup.py
===================================================================
--- zc.testbrowser/trunk/setup.py 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/setup.py 2009-04-28 20:13:37 UTC (rev 99565)
@@ -16,11 +16,20 @@
long_description = (
open('README.txt').read()
- + open('CHANGES.txt').read()
- + '.. contents::\n\n\n'
- + open(os.path.join('src', 'zc', 'testbrowser', 'README.txt')).read()
+ + "\n\n%s" % open('CHANGES.txt').read()
+ + "\n\n%s" % '.. contents::\n'
+ + "\n\n%s" % open(os.path.join('src', 'zc', 'testbrowser', 'README.txt')).read()
+ + "\n\n%s" % open(os.path.join('src', 'zc', 'testbrowser', 'real.txt')).read()
+ + "\n\n%s" % open(os.path.join('src', 'zc', 'testbrowser', 'proxy.txt')).read()
+ + "\n\n%s" % open(os.path.join('src', 'zc', 'testbrowser', 'authors.txt')).read()
)
+if 'RSTTEST' in os.environ:
+ open(os.path.expanduser('~/test'), 'w').write(long_description)
+ import sys
+ sys.exit(0)
+
+
setup(
name = 'zc.testbrowser',
version = '1.0.0a6dev',
@@ -43,7 +52,7 @@
packages = find_packages('src'),
package_dir = {'': 'src'},
namespace_packages = ['zc',],
- tests_require = ['zope.testing'],
+ tests_require = ['zope.testing',],
install_requires = [
'ClientForm',
'mechanize',
@@ -51,8 +60,9 @@
'simplejson',
'zope.interface',
'zope.schema',
+ 'mozrunner',
],
-
+ extras_require={'test': ['IPython', 'mocker']},
include_package_data = True,
zip_safe = False,
)
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/README.txt
===================================================================
--- zc.testbrowser/trunk/src/zc/testbrowser/README.txt 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/README.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -1,5 +1,5 @@
Detailed Documentation
-======================
+=======================
Before being of much interest, we need to open a web page. ``Browser``
instances have a ``base`` attribute that sets the URL from which ``open``-ed
@@ -1277,17 +1277,3 @@
>>> len(browser.contents) == actual_length
True
-
-Authors
--------
-
-Benji York created testbrowser (originally zope.testbrowser) in 2005 with Gary
-Poster and Stephan Richter making large contributions.
-
-The zc.testbrowser.real version was conceptualized by Benji York in 2007 and
-after an initial implementation sketch, brought to fruition by Stephan
-Richter, Rocky Burt, Justas Sadzevicius, and others at the Foliage Zope 3
-sprint in Boston, MA during the week of September 24, 2007.
-
-There have been many other contributions from users of testbrowser that are
-greatly appreciated.
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/authors.txt
===================================================================
--- zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/authors.txt (rev 0)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/authors.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -0,0 +1,16 @@
+Authors
+========
+
+Benji York created testbrowser (originally zope.testbrowser) in 2005 with Gary
+Poster and Stephan Richter making large contributions.
+
+The zc.testbrowser.real version was conceptualized by Benji York in 2007 and
+after an initial implementation sketch, brought to fruition by Stephan
+Richter, Rocky Burt, Justas Sadzevicius, and others at the Foliage Zope 3
+sprint in Boston, MA during the week of September 24, 2007.
+
+Mathieu Pasquet added recently proxy support and improved the real browser class.
+
+There have been many other contributions from users of testbrowser that are
+greatly appreciated.
+
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/firefox/mozrepl.xpi
===================================================================
(Binary files differ)
Property changes on: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/firefox/mozrepl.xpi
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.py
===================================================================
--- zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.py (rev 0)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.py 2009-04-28 20:13:37 UTC (rev 99565)
@@ -0,0 +1,299 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+__docformat__ = "reStructuredText"
+
+import ConfigParser
+import logging
+import mechanize
+import os
+import random
+import sys
+import time
+
+from zc.testbrowser import browser, real, utils
+
+FF2_USERAGENT = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; '\
+ 'fr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14'
+
+class BaseAnonymousBrowser:
+ """A base class to implement powerful and anonymous browser from.
+ This abstract classr may be used to write browsers that support proxies
+ balancing
+
+ """
+ def __init__(self,
+ url = None,
+ config = None,
+ proxies = None,
+ user_agent = None,
+ proxy_max_use = None,
+ mech_browser = None,
+ *args, **kwargs):
+ self._enable_setattr_errors = False
+ if not proxies:
+ proxies = []
+ if not getattr(self, 'log', None):
+ self.log = logging.getLogger(__name__)
+ self.load_config(config)
+ proxieslist = self.config.get('proxies', '').strip()
+ self.proxies = [proxy.strip()
+ for proxy in proxieslist.split('\n')
+ if proxy.strip()]
+ self.proxies.extend([p
+ for p in proxies
+ if not p in self.proxies])
+ if user_agent:
+ self.user_agent = user_agent
+ else:
+ self.user_agent = self.config.get('user-agent',
+ FF2_USERAGENT)
+ # only enter proxified mode when we got a list of valid proxies
+ self.proxified = False
+ if self.proxies:
+ self.proxified = True
+
+ # intialize proxy balancing
+ self._lastproxy = {'proxy':-1,
+ 'count':0}
+ # initiate proxy max use
+ self.proxy_max_use = proxy_max_use
+
+ def load_config(self, config):
+ if not getattr(self, 'config', None):
+ self.config = utils.get_ztb_config(config)
+
+ def chooseProxy(self):
+ choice = 0
+ if len(self.proxies) < 2:
+ # for 0 or 1 proxy, just get it
+ choice = random.randint(0, len(self.proxies)-1)
+ else:
+ # for 2+ proxies in the list, we iterate to get a different proxy
+ # for the last one used, if this one was too many used.
+ # We also put a coin of the reuse of the proxy, we just dont go too
+ # random
+ proxy_not_chosen, maxloop = True, 200
+ while proxy_not_chosen:
+ # pile or face ! We reuse the proxy or not!
+ if not self.proxy_max_use \
+ or (self._lastproxy['count'] >= 1) \
+ and (self._lastproxy['count'] < self.proxy_max_use):
+ # we do not always change proxy
+ if (self._lastproxy['proxy'] != -1) and random.randint(0, 1):
+ choice = self._lastproxy['proxy']
+ else:
+ choice = random.randint(0, len(self.proxies)-1)
+ if self._lastproxy['proxy'] == choice:
+ if not self.proxy_max_use or (self._lastproxy['count'] <= self.proxy_max_use):
+ self._lastproxy['proxy'] = choice
+ proxy_not_chosen = False
+ else:
+ self._lastproxy['proxy'] = choice
+ # reinitialize the proxy count
+ self._lastproxy['count'] = 0
+ proxy_not_chosen = False
+ maxloop -= 1
+ if not maxloop:
+ self.log.debug("Ho, seems we got the max wills "
+ "to choose, something has gone wrong")
+ proxy_not_chosen = False
+ self._lastproxy['count'] += 1
+ return self.proxies[choice]
+
+ def reset(self, url, data):
+ """Reset the underlying browser to its initial state.
+ (eg, just after init)
+ Implementation example::
+
+ try:
+ self.browser_open('about:blank')
+ except Exception, e:
+ if not ('unknown url type:' in '%s' % e):
+ raise e
+ """
+ raise Exception('not implemented')
+
+ def open(self, url, data=None, retrys=4, *args, **kwargs):
+ """Wrapper to the underlyng browser class.
+ It will do the neccessary things to proxisy the
+ browser before hitting any url.
+ @param url the url to hit
+ @param retrys number of retrys allowed before crashing.
+ """
+ try:
+ if self.proxified:
+ self.proxify()
+ if self.user_agent:
+ self.fake_user_agent()
+ return self.browser_open(url, data)
+ except Exception, e:
+ if retrys:
+ # go to open blank to reset entirely all post and other stuff
+ self.reset(url, data)
+
+ # removing dead proxies
+ if self.proxified:
+ if len(self.proxies) >= 1:
+ del self.proxies[self._lastproxy['proxy']]
+ self._lastproxy['proxy'] = -1
+ self._lastproxy['count'] = 0
+ else:
+ raise Exception("There are no valid proxies left")
+
+ self.log.error('Retrying "%s", (left: %s)' % (url, retrys))
+ retrys -= 1
+ self.open(url, data, retrys)
+ else:
+ raise e
+
+ def proxify(self, force=False):
+ """Method to choose and set a proxy."""
+ raise Exception('not implemented')
+
+ def fake_user_agent(self, force=False):
+ """Method to set the user agent."""
+ raise Exception('not implemented')
+
+ def browser_open(self, url, data=None):
+ """Real method to hit the browser.
+ Implementation example ::
+
+ browser.Browser.open(self, url, data)
+
+ """
+ raise Exception('not implemented')
+
+class AnonymousBrowser(BaseAnonymousBrowser, browser.Browser):
+ """A proxified mechanize based browser."""
+
+ def __init__(self,
+ url=None,
+ config=None,
+ mech_browser=None,
+ proxies = [],
+ user_agent=None,
+ proxy_max_use=None,
+ *args, **kwargs):
+ BaseAnonymousBrowser.__init__(self,
+ url = url,
+ config = config,
+ proxies = proxies,
+ user_agent=user_agent,
+ proxy_max_use=proxy_max_use,
+ *args, **kwargs)
+ self._enable_setattr_errors = False
+ self.test=kwargs.get('test',False)
+ if mech_browser is None:
+ mech_browser = mechanize.Browser()
+ self.mech_browser = mech_browser
+ if url is not None:
+ BaseAnonymousBrowser.open(self, url)
+
+ def reset(self, url, data):
+ pass
+
+ def fake_user_agent(self, force=False):
+ self.mech_browser.set_handle_robots(False)
+ self.mech_browser.addheaders = [('User-agent' , self.user_agent)]
+
+ def browser_open(self, url, data=None):
+ self.timer = browser.PystoneTimer()
+ self.raiseHttpErrors = True
+ return browser.Browser.open(self, url, data)
+
+ def proxify(self, force=False):
+ """"""
+ if (self.proxified or force) and self.proxies:
+ proxy = self.chooseProxy()
+ self.mech_browser.set_proxies(
+ {'http': proxy,
+ 'https': proxy}
+ )
+
+class FirefoxBrowser(BaseAnonymousBrowser, real.Browser):
+ """A proxified mechanize based browser."""
+
+ def __init__(self,
+ url=None,
+ host = None,
+ port=None,
+ firefox_binary = None,
+ profile_klass = None,
+ config=None,
+ proxies = [],
+ user_agent=None,
+ proxy_max_use=None,
+ *args, **kwargs):
+ BaseAnonymousBrowser.__init__(self,
+ url = url,
+ config = config,
+ proxies = proxies,
+ user_agent=user_agent,
+ proxy_max_use=proxy_max_use,
+ *args, **kwargs)
+ preferences= {}
+ if self.user_agent:
+ preferences["general.useragent.override"] = self.user_agent
+ real.Browser. __init__(self,
+ url=None,
+ host = host,
+ port=port,
+ firefox_binary = firefox_binary,
+ profile_klass = profile_klass,
+ config=config,
+ preferences = preferences,
+ *args, **kwargs)
+
+ if url is not None:
+ BaseAnonymousBrowser.open(self, url)
+
+ def browser_open(self, url, data=None):
+ return real.Browser.open(self, url, data)
+
+ def fake_user_agent(self, force=False):
+ """Done in __init__, you cannont change it without restarting firefox"""
+ if force:
+ user_agent_prefs = {"general.useragent.override": self.user_agent}
+ self.update_profile(user_agent_prefs)
+ self.restart_ff()
+
+ def reset(self, url, data):
+ self.restart_ff()
+ self.open(url, data)
+
+ def browser_open(self, url, data=None):
+ return real.Browser.open(self, url, data)
+
+ def proxify(self, force=False):
+ """"""
+ if (self.proxified or force) and self.proxies:
+ host, port = self.chooseProxy().split(':')
+ proxy_prefs = {
+ 'network.proxy.http': host,
+ 'network.proxy.ftp': host,
+ 'network.proxy.gopher': host,
+ 'network.proxy.socks': host,
+ 'network.proxy.ssl': host,
+ 'network.proxy.http_port': port,
+ 'network.proxy.ftp_port': port,
+ 'network.proxy.gopher_port': port,
+ 'network.proxy.socks_port': port,
+ 'network.proxy.ssl_port': port,
+ 'network.proxy.type': 1,
+ 'network.proxy.no_proxy_on': '',
+ }
+ self.update_profile(proxy_prefs)
+
+
+
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.txt
===================================================================
--- zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.txt (rev 0)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/proxy.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -0,0 +1,290 @@
+The proxified browsers
+=======================
+
+
+A proxified abstract class
+---------------------------
+
+We provide an abstract class to enable you to easily develop your own specialized proxies.
+All that you need to do is to inherit this class, and your browser one, and then play with the ``browser_open`` method.
+
+
+We need to monkey patch expand user not to alterate our configuration files in ~/
+
+ >>> config = tempfile.mkstemp()[1]
+ >>> remove(config)
+ >>> zc.testbrowser.utils.__CONFIGFILE__ = config
+
+Install some magic to get the logs
+
+ >>> from zope.testing.loggingsupport import InstalledHandler
+ >>> log_handler = InstalledHandler('zc.testbrowser.proxy')
+
+Here is how you can implement a proxified class
+
+ >>> class MyBrowser:
+ ... """My original browser"""
+ ... def __init__(self):
+ ... """."""
+ ... def open(self, *args, **kwargs):
+ ... print 'But I ll do the same proxified or not!'
+ >>>
+
+Heritage order is important !!!
+
+ >>> class ProxifiedBrowser(BaseAnonymousBrowser, MyBrowser):
+ ... """."""
+ ... def __init__(self, proxies=None, *args, **kwargs):
+ ...
+ ... # in the real life, specify real constructor arguments
+ ... BaseAnonymousBrowser.__init__(self, proxies=proxies)
+ ... MyBrowser.__init__(self)
+ ...
+ ... def reset(self):
+ ... pass
+ ... def fake_user_agent(self, force=False):
+ ... print "ua:%s" % self.user_agent
+ ... def proxify(self, force=False):
+ ... print "proxies:%s" % self.proxies
+ ... def browser_open(self, *args, **kwargs):
+ ... print 'I am wrapped'
+ ... return MyBrowser.open(self, *args, **kwargs)
+ >>>
+
+And when you instantiate it, here is the magic
+
+ >>> mybrowser = ProxifiedBrowser(proxies=['a'])
+ >>> mybrowser.open('')
+ proxies:['a']
+ ua:Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14
+ I am wrapped
+ But I ll do the same proxified or not!
+
+
+But, we want to be anonymous, and we ll set a proxy
+To define those proxies, Either:
+
+ * Set a config.ini file like::
+
+ [zc.testbrowser]
+ proxies =
+ host1:port
+ host2:port
+
+ * give a ``proxies`` list to the browser constructor.
+
+ >>> b = BaseAnonymousBrowser(proxies=['http://foo.net:3128'])
+ >>> b.proxies
+ ['http://foo.net:3128']
+
+The first time you launch the browser, if no config is present, it will be created for you in ~/.zc.testbrowser.cfg:
+
+ >>> cat(config)
+ [zc.testbrowser]
+ proxies =
+ <BLANKLINE>
+
+The implementation of the abstract class is somehow, ..., limited
+
+ >>> b.browser_open('')
+ Traceback (most recent call last):
+ Exception: not implemented
+ >>> b.proxify()
+ Traceback (most recent call last):
+ Exception: not implemented
+ >>> b.fake_user_agent()
+ Traceback (most recent call last):
+ Exception: not implemented
+ >>> b.reset(None, None)
+ Traceback (most recent call last):
+ Exception: not implemented
+
+When the browser has many proxies defined, it will circly through those ones.
+But, it will not use the same host indefinitivly, just set the ``proxy_max_use`` argument::
+
+ >>> sproxies = [proxy.replace('http:', '').replace('/', '') for proxy in proxies]
+ >>> proxy = sproxies[0]
+ >>> url = '%s/print_request' % proxies[0]
+ >>> b = AnonymousBrowser(proxies=sproxies, proxy_max_use=3)
+ >>> b.config
+ {'__name__': 'zc.testbrowser', 'proxies': ''}
+ >>> b.proxies == sproxies
+ True
+ >>> b.proxified
+ True
+
+
+The most important of the class is the proxy balancing mode.
+Naturally, a thing to verify is that we have our pseudo-random loop running.
+First thing is we will choose 2 times the 2nd proxy, then the third
+And of course, we will set the mocker to change the proxy at each row.
+
+ >>> import mocker
+ >>> import random
+ >>> mocked = mocker.Mocker()
+ >>> custom_random_int = mocked.replace('random.randint')
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(2)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(2)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(2)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(3)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(2)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> custom_random_int(0, 3)
+ <mocker.Mock object at ...>
+ >>> mocked.result(1)
+ >>> custom_random_int(0,1)
+ <mocker.Mock object at ...>
+ >>> mocked.result(0)
+ >>> mocked.replay()
+
+Live !
+
+ >>> b = AnonymousBrowser(url=url, proxies=sproxies, proxy_max_use=3)
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 2}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 2, 'proxy': 2}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 3, 'proxy': 2}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 0}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 3}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 0}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 2}
+ >>> b.open(url)
+ >>> b._lastproxy
+ {'count': 1, 'proxy': 1}
+ >>> mocked.restore()
+
+If the proxies are dead, we just remove them from the list.
+
+ >>> wproxies = [ 'localhost:35675', 'localhost:35676', 'localhost:35677', proxy,]
+ >>> mybrowser = AnonymousBrowser(proxies=wproxies, proxy_max_use=3)
+ >>> mybrowser.proxies
+ ['localhost:35675', 'localhost:35676', 'localhost:35677', 'localhost:...']
+ >>> mybrowser.open(url)
+ >>> mybrowser.proxies
+ ['localhost:...']
+
+This may arrive, your proxies list is totally invalid, no proxy can be reached
+
+ >>> mybrowser.proxies = ['localhost:invalid']
+ >>> mybrowser.open(url)
+ Traceback (most recent call last):
+ ...
+ Exception: There are no valid proxies left
+
+
+The loop is recursion protected. If we return always the same host, so the chooser cannot choose anything else.
+It will loop until it crashes or it handle the recursion::
+
+ >>> def randomint(a,b):
+ ... return 2
+ >>> import random; random.randint = randomint
+ >>> b2 = AnonymousBrowser(proxies=sproxies, proxy_max_use=3)
+ >>> b2.proxy_max_use
+ 3
+ >>> b2._lastproxy['count']
+ 0
+ >>> b2.chooseProxy()
+ '...
+ >>> b2._lastproxy['count']
+ 1
+ >>> b2.chooseProxy()
+ '...
+ >>> b2._lastproxy['count']
+ 2
+ >>> b2.chooseProxy()
+ '...
+ >>> b2._lastproxy['count']
+ 3
+ >>> b2.chooseProxy()
+ '...
+ >>> b2.chooseProxy()
+ 'localhost:...'
+ >>> log_handler.records[-1].msg
+ 'Ho, seems we got the max wills to choose, something has gone wrong'
+
+Controlling automaticly the User Agent
+------------------------------------------
+Hay, we have a brand new default user agent::
+
+ >>> br = AnonymousBrowser()
+ >>> br.open(url)
+ >>> FF2_USERAGENT in br.contents
+ True
+ >>> br2 = AnonymousBrowser(url)
+ >>> FF2_USERAGENT in br2.contents
+ True
+
+The mechanize proxified browser
+----------------------------------
+Use this browser to have a proxified version of the
+basic mechanize browser (zc.testbrowser.browser.Browser)
+
+ >>> b = AnonymousBrowser(proxies=sproxies,**{"test":True})
+ >>> b.open('%s/print_request' % url)
+ >>> 'Host: localhost:' in b.contents
+ True
+ >>> b._lastproxy['count'] == 1
+ True
+ >>> b._lastproxy['proxy'] in [0,1,2,3,4]
+ True
+
+The firefox based anonymous browser
+---------------------------------------
+
+ >>> noecho = os.system("ps aux|grep firefox|awk '{print $2}'|xargs kill -9")
+ >>> ff = FirefoxBrowser(url=url, proxies = sproxies)
+ >>> 'Host: localhost:' in ff.contents
+ True
+ >>> FF2_USERAGENT in ff.contents
+ True
+ >>> ff.stop_ff()
+
+Cleanup
+-----------
+
+ >>> remove(config)
+ >>> remove(ff.firefox_profile.profile)
+
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.py
===================================================================
--- zc.testbrowser/trunk/src/zc/testbrowser/real.py 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.py 2009-04-28 20:13:37 UTC (rev 99565)
@@ -1,3 +1,18 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import logging
+import os
import os.path
import re
import simplejson
@@ -4,15 +19,75 @@
import socket
import telnetlib
import tempfile
+import signal
import time
import urlparse
+
import zc.testbrowser.browser
import zc.testbrowser.interfaces
+from zc.testbrowser import utils
+
import zope.interface
+import mozrunner
+
PROMPT = re.compile('repl\d?> ')
CONTINUATION_PROMPT = re.compile('\\.\\.\\.\\.\d?> ')
+class MozReplProfile(mozrunner.FirefoxProfile):
+ """A mozrepl enabled firefox profile"""
+
+ def set_preferences(self, preferences):
+ """Adds preferences dict to profile preferences"""
+ pref_lines = ['user_pref(%s, %s);' %
+ (simplejson.dumps(k),
+ simplejson.dumps(v).replace('\/', '/' )) for k, v in
+ preferences.items()]
+ prefs_file = os.path.join(self.profile, 'user.js')
+ gen_prefs_file = os.path.join(self.profile, 'prefs.js')
+ for fp in prefs_file, gen_prefs_file:
+ f = open(fp, 'a+')
+ f.write('\n#MozRunner Prefs Start\n')
+ for line in pref_lines:
+ f.write(line+'\n')
+ f.write('#MozRunner Prefs End\n')
+ f.flush()
+ f.close()
+
+ def __init__(self,
+ default_profile=None,
+ profile=None,
+ create_new=True,
+ plugins=[],
+ preferences={},
+ port=4242,
+ *args, **kwargs):
+ """See mozrunner code for documentation.
+ port: port where mozrepl should listen on"""
+ plugins.append(
+ os.path.join(os.path.dirname(__file__), 'firefox', 'mozrepl.xpi')
+ )
+ # update preferences to activate mozrepl on firefox startup
+ # depending the mozrepl version, keys can changed!
+ self.preferences.update(
+ {'extensions.mozlab.mozrepl.autoStart': True,
+ 'extensions.mozlab.mozrepl.loopbackOnly': False,
+ 'extensions.mozlab.mozrepl.port': port,
+ 'extensions.mozlab.mozrepl.autoStart': True,
+ 'extensions.mozrepl.autoStart': True,
+ 'extensions.mozrepl.loopbackOnly': False,
+ 'extensions.mozrepl.port': port,
+ 'extensions.mozrepl.autoStart': True,
+ }
+ )
+ mozrunner.FirefoxProfile.__init__(self,
+ default_profile=default_profile,
+ profile=profile,
+ create_new=create_new,
+ plugins=plugins,
+ preferences=preferences,
+ *args, **kwargs)
+
class BrowserStateError(RuntimeError):
pass
@@ -20,7 +95,6 @@
class AmbiguityError(ValueError):
pass
-
def disambiguate(intermediate, msg, index):
if intermediate:
if index is None:
@@ -94,6 +168,9 @@
class Browser(zc.testbrowser.browser.SetattrErrorsMixin):
+ """A firefox based browser controller.
+ It supports firefox launching through mozrunner if the host is localhost
+ """
zope.interface.implements(zc.testbrowser.interfaces.IBrowser,
zc.testbrowser.interfaces.IWait)
@@ -103,17 +180,58 @@
_counter = 0
timeout = 60
- def __init__(self, url=None, host='localhost', port=4242):
+ def __init__(self,
+ url=None,
+ host = None,
+ port=None,
+ firefox_binary = None,
+ profile_klass = None,
+ config=None,
+ preferences = None,
+ *args, **kwargs):
+
+ self._enable_setattr_errors = False
+ self.log = logging.getLogger(__name__)
self.js = JSProxy(self.execute)
- self.init_repl(host, port)
- self._enable_setattr_errors = True
+ self.config = utils.get_ztb_config(config)
+ self.host = host
+ self.port = port
+ if not profile_klass:
+ profile_klass = MozReplProfile
+ if not preferences:
+ preferences = {}
+ # those are path location only !
+ self.MOZILLA_BINARY = firefox_binary
+ if not self.host:
+ self.host = self.config.get('firefox-host', 'localhost')
+ if not port:
+ self.port = self.config.get('firefox-port', 4242)
+ if not self.MOZILLA_BINARY:
+ self.MOZILLA_BINARY = self.config.get('firefox',
+ os.environ.get('FIREFOX', 'firefox')
+ ).strip()
+ # for local addresses, just load directly the file, its really faster
+ hosts = socket.gethostbyaddr(socket.getaddrinfo(self.host, 0)[0][4][0])[1]
+ self.is_local = 'localhost' in hosts
+ # if we are local, we are just enought smarts to handle firefox
+ # starts/stops
+ self.firefox_profile, self.firefox = None, None
+ if self.is_local:
+ self.firefox_profile = profile_klass(port=self.port, preferences=preferences)
+ self.firefox = mozrunner.FirefoxRunner(binary=utils.which(self.MOZILLA_BINARY),
+ profile=self.firefox_profile)
+ self.firefox_running = False
+ # this will be a no-op if we are not attacking a local mozrepl.
+ self.start_ff()
if url is not None:
self.open(url)
def init_repl(self, host, port):
try:
+ self._enable_setattr_errors = False
self.telnet = telnetlib.Telnet(host, port)
+ self._enable_setattr_errors = True
except socket.error, e:
raise RuntimeError('Error connecting to Firefox at %s:%s.'
' Is MozRepl running?' % (host, port))
@@ -125,21 +243,30 @@
self.load_file(js_path)
def load_file(self, file_path):
- for line in open(file_path, 'r'):
- self.telnet.write(line)
- self.expect([PROMPT, CONTINUATION_PROMPT])
+ # for local addresses, just load directly the file, its really faster
+ self.assert_repl_initialized()
+ hosts = socket.gethostbyaddr(
+ socket.getaddrinfo(self.telnet.host, 0)[0][4][0]
+ )[1]
+ if self.is_local:
+ self.telnet.write('repl.load("file://%s")' % file_path)
+ else:
+ for line in open(file_path, 'r'):
+ self.telnet.write(line)
+ self.expect([PROMPT, CONTINUATION_PROMPT])
def execute(self, js):
+ self.assert_repl_initialized()
if not js.strip():
return
if not js.endswith('\n'):
js = js + '\n'
- self.telnet.write("'MARKER'\n")
- self.telnet.read_until('MARKER', self.timeout)
+ # wipe the line from previous dusts in the channel
+ self.telnet.write("\n;\n")
+ #print self.telnet.read_until('MARKER', self.timeout)
self.expect()
self.telnet.write(js)
i, match, text = self.expect()
- #if '!!!' in text: import pdb;pdb.set_trace() # XXX debug only, remove
if '!!!' in text: raise Exception('FAILED: ' + text + ' in ' + js)
result = text.rsplit('\n', 1)
if len(result) == 1:
@@ -159,7 +286,11 @@
def getAttributes(self, tokens, attr_name):
return self.js.tb_extract_token_attrs(tokens, attr_name)
+ def assert_repl_initialized(self):
+ assert getattr(self, 'telnet', None), 'MozRepl is not initialized'
+
def expect(self, expected=None):
+ self.assert_repl_initialized()
if expected is None:
expected = [PROMPT]
i, match, text = self.telnet.expect(expected, self.timeout)
@@ -185,6 +316,14 @@
url = url.split(token)[0]
return url
+
+ def update_profile(self, prefs=None):
+ if prefs:
+ self.firefox.profile.preferences.update(prefs)
+ self.firefox_profile.set_preferences(
+ self.firefox_profile.preferences
+ )
+
def wait(self):
start = time.time()
while self.execute('tb_page_loaded') == 'false':
@@ -192,7 +331,14 @@
if time.time() - start > self.timeout:
raise RuntimeError('timed out waiting for page load')
- assert self.execute('tb_page_loaded;') == 'true'
+ #ret = self.execute('tb_page_loaded;')
+ retrys = 100
+ assertion = None
+ while retrys and not assertion:
+ retrys -= 1
+ time.sleep(0.01)
+ assertion = self.execute('tb_page_loaded;')
+ assert assertion == 'true'
while self.execute('tb_page_loaded;') == 'true':
self.execute('tb_page_loaded = false;')
@@ -210,8 +356,6 @@
finally:
self._changed()
- # TODO raise non-200 errors
-
@property
def isHtml(self):
return self.execute('content.document.contentType') == 'text/html'
@@ -229,10 +373,8 @@
@property
def contents(self):
base, sub = self.execute('content.document.contentType').split('/')
- if base == 'text' and 'html' not in sub:
- return self.execute(
- "content.document.getElementsByTagName('pre')[0].innerHTML")
- return self.execute('tb_get_contents()')
+ command = 'tb_get_contents()'
+ return self.execute(command)
def reload(self):
self.execute('content.document.location = content.document.location')
@@ -327,7 +469,107 @@
return Form(self, form_token)
+ def exec_contentjs(self, cmd):
+ d = {'s': self.getPrompt(), 'cmd': cmd}
+ try:
+ self.home()
+ ret = self.execute("this.content.%(cmd)s; " % d)
+ except Exception, e:
+ raise
+ finally:
+ self.home()
+ return ret
+ def quit_mozrepl(self):
+ self._enable_setattr_errors = False
+ self._prompt = None
+ try:
+ self.telnet.close()
+ except Exception, e:
+ pass
+ try:
+ delattr(self, 'telnet')
+ except Exception, e:
+ pass
+ self._enable_setattr_errors = True
+
+ def home(self):
+ self.execute("%s.home()" % self.getPrompt())
+
+ def getPrompt(self, force = True):
+ self.assert_repl_initialized()
+ self.telnet.write("\n;\n")
+ if not getattr(self, '_prompt', None) or force:
+ a, g, c = self.expect()
+ self._enable_setattr_errors = False
+ self._prompt = re.sub('> .*', '', g.group())
+ self._enable_setattr_errors = True
+ return getattr(self, '_prompt', 'repl')
+
+ def exec_in_ff_dir(self, f, *args, **kwargs):
+ """Runs the runner in the firefox directory, if any
+ If firefox is not runned on a standart location,
+ there are chances you ll get dynamic libraries problems.
+ Solution is to be chdir'ed prior to the firefox launch"""
+ ret, cwd = None, os.getcwd()
+ if self.is_local:
+ d = os.path.dirname(self.firefox.binary)
+ os.chdir(d)
+ try:
+ ret = f(*args, **kwargs)
+ os.chdir(cwd)
+ except Exception, e:
+ os.chdir(cwd)
+ raise
+ return ret
+
+ def start_ff(self):
+ """Starts firefox, only if firefox isnt running already."""
+ if not self.firefox_running:
+ self.exec_in_ff_dir(self.firefox.start)
+ time.sleep(1)
+ retry = 60
+ while retry:
+ retry -= 1
+ time.sleep(1)
+ try:
+ self.init_repl(self.host, self.port)
+ retry = False
+ except Exception, e:
+ if not retry:
+ raise
+ # considere that firefox is running only if both the couple:
+ # firefox / MozRepl connexion is achieved.
+ self.firefox_running = True
+
+ def stop_ff(self):
+ """Stops firefox, only if firefox is running."""
+ if self.firefox_running:
+ self.exec_in_ff_dir(
+ self.firefox.kill,
+ signal.SIGKILL
+ )
+ self.quit_mozrepl()
+ self.firefox_running = False
+
+ def restart_ff(self):
+ self.stop_ff()
+ time.sleep(1)
+ self.start_ff()
+ time.sleep(1)
+
+ def screenshot(self, path=".", name="screenshot"):
+ if not os.path.exists(path):
+ os.makedirs(path)
+ fpath = os.path.join(path, "%s.png" % name)
+ self.execute('tb_take_screen_shot("%s")' % fpath)
+ timeout = 12000
+ while not os.path.isfile(fpath) or not timeout:
+ timeout -= 1
+ time.sleep(0.01)
+ if not timeout:
+ raise 'Timeout while taking shot!'
+
class Link(zc.testbrowser.browser.SetattrErrorsMixin):
zope.interface.implements(zc.testbrowser.interfaces.ILink)
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.txt
===================================================================
--- zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.txt (rev 0)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/real.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -0,0 +1,91 @@
+
+Controlling rael browsers: the firefox case
+=====================================================
+We will use an extension, **mozrepl**, to control firefox.
+It's a little piece of software that enables you to connect to your firefox via telnet, and controls what's controllable via javascript.
+See http://wiki.github.com/bard/mozrepl for further documentation .
+
+The profile
+-----------------------------
+Configuring firefox can be a heck, we will provide a default profile, whith mozrepl installed a configured to run on localhost/4242.
+We configured also this profile to stop firefox being interactive (eg: the session restore thing)
+
+ >>> profile = MozReplProfile()
+ >>> profile.profile
+ '...mozrunner'
+ >>> profile.preferences
+ {'browser.shell.checkDefaultBrowser': False, 'extensions.mozrepl.loopbackOnly': False, 'browser.sessionstore.resume_from_crash': False, 'browser.warnOnQuit': False, 'extensions.update.enabled': False, 'browser.tabs.warnOnClose': False, 'extensions.update.notifyUser': False, 'extensions.mozlab.mozrepl.port': 4242, 'extensions.mozlab.mozrepl.autoStart': True, 'extensions.mozrepl.autoStart': True, 'extensions.mozlab.mozrepl.loopbackOnly': False, 'extensions.mozrepl.port': 4242}
+
+ >>> profile.plugins
+ ['...zc/testbrowser/firefox/mozrepl.xpi']
+ >>> profile.plugins_installed
+ ['...mozrunner/extensions/mozrepl at hyperstruct.net']
+
+Controlling firefox
+--------------------------------
+
+ >>> noecho = os.system("ps aux|grep firefox|awk '{print $2}'|xargs kill -9")
+ >>> url = '%s/print_request' % proxies[0]
+ >>> b = RealBrowser(url)
+ >>> print b.contents
+ <html>...
+ >>> b.firefox_running
+ True
+
+Stopping it
+--------------------
+
+ >>> b.stop_ff()
+ >>> b.firefox_running
+ False
+ >>> b.contents
+ Traceback (most recent call last):
+ ...
+ AssertionError: MozRepl is not initialized
+
+Restarting it
+-------------------
+
+ >>> b.restart_ff()
+ >>> b.firefox_running
+ True
+
+Taking screenshots
+-------------------------
+You can take screenshots of the running firefox, too::
+
+ >>> f = tempfile.mkdtemp()
+ >>> b.screenshot(f, "screenshot")
+ >>> 'PNG' in open(os.path.join(f, "screenshot.png")).read()
+ True
+
+
+Executing arbitrary JavaScript in the current context
+-------------------------------------------------------------
+
+ >>> b.open(url)
+ >>> b.url
+ 'http://localhost:.../print_request'
+ >>> b.exec_contentjs('content.location')
+ 'http://localhost:.../print_request \xe2\x80\x94 {host: "localhost:...", hostname: "localhost", port: "..."}'
+
+
+Configuration settings
+--------------------------------------
+
+You can play with some keys in the section ``zc.testbrowser`` if you provide a configuration file::
+
+ - firefox-host
+ mozrepl host
+ - firefox-port
+ mozrepl-port
+ - firefox
+ firefox binary to use
+
+Cleaning
+----------------
+
+ >>> b.stop_ff()
+ >>> remove(b.firefox_profile.profile)
+ >>> remove(f)
+
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/screen-shots.txt
===================================================================
--- zc.testbrowser/trunk/src/zc/testbrowser/screen-shots.txt 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/screen-shots.txt 2009-04-28 20:13:37 UTC (rev 99565)
@@ -1,4 +1,13 @@
+Taking screenshots
+----------------------------
+
>>> from zc.testbrowser.real import Browser
- >>> browser = Browser()
- >>> browser.open('http://localhost:%s/index.html' % TEST_PORT)
- >>> browser.execute('tb_take_screen_shot("/tmp/1.png")')
+ >>> import tempfile
+ >>> f = tempfile.mkdtemp()
+ >>> browser = Browser('http://localhost:%s/print_request' % TEST_PORT)
+ >>> browser.screenshot(f)
+ >>> browser.stop_ff()
+ >>> 'PNG' in open(os.path.join(f, "screenshot.png")).read()
+ True
+
+
Modified: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/tests.py
===================================================================
--- zc.testbrowser/trunk/src/zc/testbrowser/tests.py 2009-04-23 04:59:07 UTC (rev 99416)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/tests.py 2009-04-28 20:13:37 UTC (rev 99565)
@@ -24,16 +24,28 @@
import random
import re
import string
+import socket
+import tempfile
import threading
import unittest
import urllib
import urllib2
import zc.testbrowser.browser
+import zc.testbrowser.proxy
import zc.testbrowser.real
+import zc.testbrowser.utils
+import socket
+# will be gloabals in test.
+from zc.buildout.testing import cat, ls, remove
+from zc.testbrowser.real import Browser as RealBrowser
+from zc.testbrowser.real import MozReplProfile
+from zc.testbrowser.proxy import BaseAnonymousBrowser, FirefoxBrowser, AnonymousBrowser, FF2_USERAGENT
+
web_server_base_path = os.path.join(os.path.split(__file__)[0], 'ftests')
+#socket.setdefaulttimeout(20)
class TestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -44,6 +56,21 @@
return 'Mon, 17 Sep 2007 10:05:42 GMT'
def do_GET(self):
+ if self.path.endswith('/print_request'):
+ self.end_headers()
+ self.send_response(200, '\n\n\html><body>'
+ '<pre>%s</pre>'
+ '</body></html>' % self.headers)
+ return
+
+ if self.path == '/':
+ self.end_headers()
+ self.send_response(200,
+ '\n\n<html><body>'
+ '<pre>\nYou are on r00t\n</pre>'
+ '</body></html>')
+ return
+
if self.path.endswith('robots.txt'):
self.send_response(404)
self.send_header('Connection', 'close')
@@ -52,6 +79,7 @@
try:
f = open(web_server_base_path + self.path)
except IOError:
+
self.send_response(500)
self.send_header('Connection', 'close')
return
@@ -264,8 +292,8 @@
>>> browser.open('''\
... <html><body>
... <form action="." method="post" enctype="multipart/form-data">
- ... <input type="submit" name="submit_me" value=" GOOD " />
- ... <input type="submit" name="submit_me" value=" BAD " />
+ ... <input type="submit" name="submit_me" value=" GOOD" />
+ ... <input type="submit" name="submit_me" value=" BAD" />
... </form></body></html>
... ''') # doctest: +ELLIPSIS
GET / HTTP/1.1
@@ -273,7 +301,7 @@
>>> browser.getControl('BAD')
<SubmitControl name='submit_me' type='submit'>
>>> browser.getControl('BAD').value
- ' BAD '
+ ' BAD'
>>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF
POST / HTTP/1.1
Content-length: 176
@@ -285,7 +313,7 @@
-----------------------------100167997466992641913031254
Content-disposition: form-data; name="submit_me"
<BLANKLINE>
- BAD
+ BAD
-----------------------------100167997466992641913031254--
<BLANKLINE>
@@ -432,13 +460,12 @@
])
def serve_requests(server):
- global server_stop
- while not server_stop:
+ server.stop = False
+ while not server.stop:
server.handle_request()
- server.server_close()
def setUpServer(test):
- global server_stop
+ global server_stop, ports
server_stop = False
port = random.randint(20000, 30000)
test.globs['TEST_PORT'] = port
@@ -447,10 +474,30 @@
thread.setDaemon(True)
thread.start()
test.globs['web_server_thread'] = thread
+ test.globs['server'] = server
+ test.globs['tempfile'] = tempfile
+ test.globs['cat'] = cat
+ test.globs['os'] = os
+def setUpProxyServers(test):
+ server_stop = False
+ test.globs['proxies'] = []
+ test.globs['web_server_threads'] = []
+ test.globs['servers'] = []
+ for i in range(4):
+ port = random.randint(20000, 30000)
+ test.globs['TEST_PORT'] = port
+ test.globs['proxies'].append('http://localhost:%s' % port)
+ server = BaseHTTPServer.HTTPServer(('localhost', port), TestHandler)
+ thread = threading.Thread(target=serve_requests, args=[server])
+ thread.setDaemon(True)
+ thread.start()
+ test.globs['web_server_threads'].append(thread)
+ test.globs['servers'].append(server)
+ test.globs.update(globals())
+
def tearDownServer(test):
- global server_stop
- server_stop = True
+ test.globs['server'].stop = True
# make a request, so the last call to `handle_one_request` will return
try:
urllib.urlretrieve('http://localhost:%d/' % test.globs['TEST_PORT'])
@@ -458,6 +505,18 @@
pass # it's ok, server is already dead
test.globs['web_server_thread'].join()
+def tearDownProxyServers(test):
+ for server in test.globs['servers']:
+ server.stop = True
+ # make a request, so the last call to `handle_one_request` will return
+ try:
+ urllib.urlretrieve('http://localhost:%d/' % server.server_port)
+ except IOError:
+ pass # it's ok, server is already dead
+ if 'web_server_threads' in test.globs:
+ for t in test.globs['web_server_threads']:
+ t.join()
+
def setUpReal(test):
test.globs['Browser'] = zc.testbrowser.real.Browser
setUpServer(test)
@@ -486,14 +545,28 @@
checker=checker, setUp=setUpReal, tearDown=tearDownServer)
real_readme.level = 3
+ proxy = doctest.DocFileSuite('proxy.txt', optionflags=flags,
+ setUp=setUpProxyServers, tearDown=tearDownProxyServers)
+
+ real = doctest.DocFileSuite('real.txt', optionflags=flags,
+ setUp=setUpProxyServers, tearDown=tearDownProxyServers)
+
+ this_file = doctest.DocTestSuite(checker=checker)
+
screen_shots = doctest.DocFileSuite('screen-shots.txt', optionflags=flags,
setUp=setUpServer, tearDown=tearDownServer)
- screen_shots.level = 3
- this_file = doctest.DocTestSuite(checker=checker)
+ return unittest.TestSuite(
+ (
+ this_file,
+ readme,
+ real_readme,
+ headers,
+ performance,
+ real,
+ proxy,
+ )
+ )
- return unittest.TestSuite((this_file, readme, real_readme, headers,
- performance, screen_shots))
-
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
Added: zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/utils.py
===================================================================
--- zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/utils.py (rev 0)
+++ zc.testbrowser/branches/fastreal_screenshots_mozrunner_proxys/src/zc/testbrowser/utils.py 2009-04-28 20:13:37 UTC (rev 99565)
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+__docformat__ = "reStructuredText"
+
+import ConfigParser
+import logging
+import os
+
+__CONFIG_SECTION__ = 'zc.testbrowser'
+__CONFIGFILE__ = os.path.expanduser('~/.zc.testbrowser.cfg')
+
+def get_ztb_config(config=None):
+ """If config is a str, just try to read the __CONFIG_SECTION__
+ in config and return it.
+ Ensure also that config is a dict.
+ """
+ if not config:
+ config = ''
+ if isinstance(config, str):
+ configreader = ConfigParser.ConfigParser()
+ # only generate a config file if we want to use proxies
+ if not config:
+ config = __CONFIGFILE__
+ if config and not os.path.exists(config):
+ logging.getLogger(__name__).debug('Generating config file for '
+ 'storing your %s informaton '
+ 'in %s.' % (config, __name__))
+ configreader.write(config)
+ configreader.add_section(__CONFIG_SECTION__)
+ configreader.set(__CONFIG_SECTION__, 'proxies', '')
+ configreader.write(open(config, 'w'))
+ configreader.read(config)
+ config = configreader._sections.get(__CONFIG_SECTION__, {})
+ assert isinstance(config, dict)
+ return config
+
+def which(program, environ=None, key = 'PATH', split = ':'):
+ if not environ:
+ environ = os.environ
+ PATH=environ.get(key, '').split(split)
+ fp = None
+ if '/' in program:
+ fp = os.path.abspath(program)
+ if not fp:
+ for entry in PATH:
+ fp = os.path.abspath(os.path.join(entry, program))
+ if os.path.exists(fp):
+ break
+ if os.path.exists(fp):
+ return fp
+ raise IOError('Program not fond: %s in %s ' % (program, PATH))
+
More information about the Checkins
mailing list