# Note: may be Apache 2.0 license-contaminated. # (I haven't checked whether there is a significant license compatibility issue here.) import os, logging import tempfile import windmill from windmill.bin import admin_lib from twisted.internet import defer from foolscap.api import eventually from allmydata.util import log, fileutil from allmydata.scripts.create_node import create_node, create_introducer from allmydata.scripts.startstop_node import do_start, do_stop from time import sleep class TiltingMixin: # adapted from # http://github.com/windmill/windmill/blob/master/windmill/authoring/unit.py # http://github.com/windmill/windmill/blob/master/windmill/bin/shell_objects.py def setUp(self): self.browser_debugging = True self.browser_name = "firefox" self.web_port = "9999" self.test_url = "/" self._js_test_details = [] self.settings = { 'EXIT_ON_DONE': True, 'CONSOLE_LOG_LEVEL': logging.CRITICAL} fileutil.make_dirs("tilting") self.root = os.path.join(os.path.abspath("."), "tilting") self.public_html_path = os.path.join(self.root, "storage", "public_html") self.configure() log.msg("starting tahoe nodes") self._start_tahoe_nodes() log.msg("copying application") self.copy_application() log.msg("setting up Windmill for browser '%s'" % (self.browser_name)) windmill.block_exit = True # Windmill loves to output all sorts of stuff windmill.stdout = tempfile.TemporaryFile() admin_lib.configure_global_settings(logging_on=False) for (setting, value) in self.settings.iteritems(): windmill.settings[setting] = value windmill.settings['controllers'] = [] windmill.settings['TEST_URL'] = 'http://127.0.0.1:%s/%s' % (self.web_port, self.test_url) self.shell_objects = admin_lib.setup() self.jsonrpc = self.shell_objects['httpd'].jsonrpc_methods_instance self.jsonrpc_app = self.shell_objects['httpd'].namespaces['windmill-jsonrpc'] # Windmill prints success/failure statistics on its own # and this unfortunately seems to be the only way to stop it from doing that. # This is just a stripped down version of teardown method from windmill.server.convergence.JSONRPCMethods def _windmill_teardown(**kwargs): admin_lib.teardown(admin_lib.shell_objects_dict) windmill.runserver_running = False sleep(.25) #del self.jsonrpc_app.__dict__[u'teardown'] self.jsonrpc_app.__dict__[u'teardown'] = _windmill_teardown if self.settings['JAVASCRIPT_TEST_DIR']: self._log_js_test_results() log.msg("starting browser") self.shell_objects['start_' + self.browser_name]() d = defer.Deferred() admin_lib.on_ide_awake.append(lambda: eventually(d.callback, None)) d.addCallback(lambda ign: log.msg("browser started")) if self.browser_debugging: self.xmlrpc = windmill.tools.make_xmlrpc_client() d.addCallback(lambda ign: self.xmlrpc.add_command({'method':'commands.setOptions', 'params':{'runTests':False, 'priority':'normal'}})) return d def tearDown(self): windmill.block_exit = False if self.browser_debugging: self.xmlrpc.add_command({'method':'commands.setOptions', 'params':{'runTests':True, 'priority':'normal'}}) else: log.msg("shutting down browser '%s'" % (self.browser_name)) admin_lib.teardown(self.shell_objects) log.msg("browser shutdown done") log.msg("shutting down Tahoe nodes") self._stop_tahoe_nodes() log.msg("Tahoe nodes shut down") fileutil.rm_dir("tilting") def _start_tahoe_nodes(self): out = tempfile.TemporaryFile() start_options = {'syslog': False, 'profile': None} create_introducer("tilting/introducer", {'nickname': 'tilting-test-introducer'}, out=out, err=out) do_start("tilting/introducer", start_options, out=out, err=out) furl_path = "tilting/introducer/introducer.furl" # TODO: Once Python API for creating/starting/stopping/destroying nodes # is written this should be replaced while not os.path.isfile(furl_path): sleep(1) introducer_furl = fileutil.read(furl_path).strip() create_node("tilting/storage", {'introducer': introducer_furl, 'nickname': 'tilting-test-storage-node', 'webport': str(self.web_port)}, out=out, err=out) do_start("tilting/storage", start_options, out=out, err=out) def _stop_tahoe_nodes(self): out = tempfile.TemporaryFile() do_stop("tilting/introducer", out=out, err=out) do_stop("tilting/storage", out=out, err=out) def _log_js_test_results(self): # When running JS tests in windmill, only a "X tests of Y failed" string is printed # when all tests finished. This replaces Windmill's reporting method so that # all test results are collected in self._js_test_details and later reported # their succes is reported to Trial via self.failUnless(). This way Trial can easily # pickup which tests fail. def _report_without_resolve(**kwargs): self.jsonrpc._test_resolution_suite.report_without_resolve(*kwargs) self._js_test_details.append(kwargs) return 200 del self.jsonrpc_app.__dict__[u'report_without_resolve'] self.jsonrpc_app.register_method(_report_without_resolve, u'report_without_resolve') class JSTestsMixin: """ Mixin for running tests written in JavaScript. Remember to set self.settings['JS_TESTS_DIR'] (path is relative to _trial_tmp) as well as self.test_url. """ def test_js(self): for test in self._js_test_details: self.failUnless(test['result'], test['debug']) class Chrome(TiltingMixin, unittest.TestCase): """Starts tests in Chrome.""" def configure(self): self.browser_name = "chrome" class Firefox(TiltingMixin, unittest.TestCase): """Starts tests in Firefox.""" def configure(self): self.browser_name = "firefox" class InternetExplorer(TiltingMixin, unittest.TestCase): """Starts tests in Internet Explorer.""" def configure(self): self.browser_name = "ie" class Safari(TiltingMixin, unittest.TestCase): """Starts tests in Safari.""" def configure(self): self.browser_name = "safari"