Ticket #1001: tilting3.py

File tilting3.py, 6.3 KB (added by josipl, at 2010-05-13T19:56:46Z)
Line 
1# Note: may be Apache 2.0 license-contaminated.
2# (I haven't checked whether there is a significant license compatibility issue here.)
3
4import os, logging
5import tempfile
6import windmill
7from windmill.bin import admin_lib
8from twisted.internet import defer
9from foolscap.api import eventually
10from allmydata.util import log, fileutil
11from allmydata.scripts.create_node import create_node, create_introducer
12from allmydata.scripts.startstop_node import do_start, do_stop
13from time import sleep
14
15class TiltingMixin:
16  # adapted from
17  # http://github.com/windmill/windmill/blob/master/windmill/authoring/unit.py
18  # http://github.com/windmill/windmill/blob/master/windmill/bin/shell_objects.py
19 
20  def setUp(self):
21    self.browser_debugging = True
22    self.browser_name = "firefox"
23    self.web_port = "9999"
24    self.test_url = "/"
25    self._js_test_details = []
26    self.settings = {
27      'EXIT_ON_DONE': True,
28      'CONSOLE_LOG_LEVEL': logging.CRITICAL}
29   
30    fileutil.make_dirs("tilting")
31    self.root = os.path.join(os.path.abspath("."), "tilting")
32    self.public_html_path = os.path.join(self.root, "storage", "public_html")
33   
34    self.configure()
35   
36    log.msg("starting tahoe nodes")
37    self._start_tahoe_nodes()
38   
39    log.msg("copying application")
40    self.copy_application()
41   
42    log.msg("setting up Windmill for browser '%s'" % (self.browser_name))
43    windmill.block_exit = True
44    # Windmill loves to output all sorts of stuff
45    windmill.stdout = tempfile.TemporaryFile()
46   
47    admin_lib.configure_global_settings(logging_on=False)
48    for (setting, value) in self.settings.iteritems():
49      windmill.settings[setting] = value
50   
51    windmill.settings['controllers'] = []
52    windmill.settings['TEST_URL'] = 'http://127.0.0.1:%s/%s' % (self.web_port, self.test_url)
53   
54    self.shell_objects = admin_lib.setup()
55    self.jsonrpc = self.shell_objects['httpd'].jsonrpc_methods_instance
56    self.jsonrpc_app = self.shell_objects['httpd'].namespaces['windmill-jsonrpc']
57   
58    # Windmill prints success/failure statistics on its own
59    # and this unfortunately seems to be the only way to stop it from doing that.
60    # This is just a stripped down version of teardown method from windmill.server.convergence.JSONRPCMethods
61    def _windmill_teardown(**kwargs):
62      admin_lib.teardown(admin_lib.shell_objects_dict)
63      windmill.runserver_running = False
64      sleep(.25)
65   
66    #del self.jsonrpc_app.__dict__[u'teardown']
67    self.jsonrpc_app.__dict__[u'teardown'] = _windmill_teardown
68   
69    if self.settings['JAVASCRIPT_TEST_DIR']:
70      self._log_js_test_results()
71   
72    log.msg("starting browser")
73    self.shell_objects['start_' + self.browser_name]()
74   
75    d = defer.Deferred()
76    admin_lib.on_ide_awake.append(lambda: eventually(d.callback, None))
77    d.addCallback(lambda ign: log.msg("browser started"))
78   
79    if self.browser_debugging:
80      self.xmlrpc = windmill.tools.make_xmlrpc_client()
81      d.addCallback(lambda ign:
82        self.xmlrpc.add_command({'method':'commands.setOptions',
83                                 'params':{'runTests':False, 'priority':'normal'}}))
84    return d
85 
86  def tearDown(self):
87    windmill.block_exit = False
88    if self.browser_debugging:
89      self.xmlrpc.add_command({'method':'commands.setOptions',
90                               'params':{'runTests':True, 'priority':'normal'}})
91    else:
92      log.msg("shutting down browser '%s'" % (self.browser_name))
93      admin_lib.teardown(self.shell_objects)
94      log.msg("browser shutdown done")
95   
96    log.msg("shutting down Tahoe nodes")
97    self._stop_tahoe_nodes()
98    log.msg("Tahoe nodes shut down")
99    fileutil.rm_dir("tilting")
100 
101  def _start_tahoe_nodes(self):
102    out = tempfile.TemporaryFile()
103    start_options = {'syslog': False, 'profile': None}
104   
105    create_introducer("tilting/introducer",
106                      {'nickname': 'tilting-test-introducer'},
107                      out=out, err=out)
108    do_start("tilting/introducer", start_options, out=out, err=out)
109   
110    furl_path = "tilting/introducer/introducer.furl"
111    # TODO: Once Python API for creating/starting/stopping/destroying nodes
112    # is written this should be replaced
113    while not os.path.isfile(furl_path):
114      sleep(1)
115   
116    introducer_furl = fileutil.read(furl_path).strip()
117   
118    create_node("tilting/storage", {'introducer': introducer_furl,
119                                    'nickname': 'tilting-test-storage-node',
120                                    'webport': str(self.web_port)}, out=out, err=out)
121    do_start("tilting/storage", start_options, out=out, err=out)
122 
123  def _stop_tahoe_nodes(self):
124    out = tempfile.TemporaryFile()
125    do_stop("tilting/introducer", out=out, err=out)
126    do_stop("tilting/storage", out=out, err=out)
127 
128  def _log_js_test_results(self):
129    # When running JS tests in windmill, only a "X tests of Y failed" string is printed
130    # when all tests finished. This replaces Windmill's reporting method so that
131    # all test results are collected in self._js_test_details and later reported
132    # their succes is reported to Trial via self.failUnless(). This way Trial can easily
133    # pickup which tests fail.
134   
135    def _report_without_resolve(**kwargs):
136      self.jsonrpc._test_resolution_suite.report_without_resolve(*kwargs)
137      self._js_test_details.append(kwargs)
138     
139      return 200
140   
141    del self.jsonrpc_app.__dict__[u'report_without_resolve']
142    self.jsonrpc_app.register_method(_report_without_resolve, u'report_without_resolve')
143
144class JSTestsMixin:
145  """
146  Mixin for running tests written in JavaScript.
147  Remember to set self.settings['JS_TESTS_DIR'] (path is relative to _trial_tmp) as well as self.test_url.
148  """
149 
150  def test_js(self):
151    for test in self._js_test_details:
152      self.failUnless(test['result'], test['debug'])
153
154class Chrome(TiltingMixin, unittest.TestCase):
155  """Starts tests in Chrome."""
156  def configure(self):
157    self.browser_name = "chrome"
158
159class Firefox(TiltingMixin, unittest.TestCase):
160  """Starts tests in Firefox."""
161  def configure(self):
162    self.browser_name = "firefox"
163
164class InternetExplorer(TiltingMixin, unittest.TestCase):
165  """Starts tests in Internet Explorer."""
166  def configure(self):
167    self.browser_name = "ie"
168
169class Safari(TiltingMixin, unittest.TestCase):
170  """Starts tests in Safari."""
171  def configure(self):
172    self.browser_name = "safari"