Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/tags/cherrypy-3.0.0/cherrypy/test/helper.py

Revision 1528 (checked in by fumanchu, 2 years ago)

Changes to socket_host:

  1. wsgiserver now treats a host of "" as an alias for INADDR_ANY. The getaddrinfo call now passes host=None and sets AI_PASSIVE in this case.
  2. Server.httpserver_from_self doesn't change an empty host ("") to localhost anymore.
  3. The test suite has a new --host=<name or IP> flag.
  4. The webtest module now allows WebCase?.HOST to be "", and will connect on '127.0.0.1' if so.
  5. Lots of comments throughout to explain that the server's treatment of socket_host="" (all IPs) is different than the client's (pick any IP).
  6. Hopefully, this will fix #619 (long delay on startup).
  • Property svn:eol-style set to native
Line 
1 """A library of helper functions for the CherryPy test suite.
2
3 The actual script that runs the entire CP test suite is called
4 "test.py" (in this folder); test.py calls this module as a library.
5
6 Usage
7 =====
8 Each individual test_*.py module imports this module (helper),
9 usually to make an instance of CPWebCase, and then call testmain().
10
11 The CP test suite script (test.py) imports this module and calls
12 run_test_suite, possibly more than once. CP applications may also
13 import test.py (to use TestHarness), which then calls helper.py.
14 """
15
16 # GREAT CARE has been taken to separate this module from test.py,
17 # because different consumers of each have mutually-exclusive import
18 # requirements. So don't go moving functions from here into test.py,
19 # or vice-versa, unless you *really* know what you're doing.
20
21 import re
22 import sys
23 import thread
24
25 import cherrypy
26 from cherrypy.lib import http, profiler
27 from cherrypy.test import webtest
28
29
30 class CPWebCase(webtest.WebCase):
31    
32     script_name = ""
33     scheme = "http"
34    
35     def prefix(self):
36         return self.script_name.rstrip("/")
37    
38     def base(self):
39         if ((self.scheme == "http" and self.PORT == 80) or
40             (self.scheme == "https" and self.PORT == 443)):
41             port = ""
42         else:
43             port = ":%s" % self.PORT
44        
45         host = self.HOST
46         if not host:
47             # The empty string signifies INADDR_ANY,
48             # which should respond on localhost.
49             host = "127.0.0.1"
50        
51         return "%s://%s%s%s" % (self.scheme, host, port,
52                                 self.script_name.rstrip("/"))
53    
54     def exit(self):
55         sys.exit()
56    
57     def tearDown(self):
58         pass
59    
60     def getPage(self, url, headers=None, method="GET", body=None, protocol=None):
61         """Open the url. Return status, headers, body."""
62         if self.script_name:
63             url = http.urljoin(self.script_name, url)
64         webtest.WebCase.getPage(self, url, headers, method, body, protocol)
65    
66     def assertErrorPage(self, status, message=None, pattern=''):
67         """Compare the response body with a built in error page.
68         
69         The function will optionally look for the regexp pattern,
70         within the exception embedded in the error page."""
71        
72         # This will never contain a traceback
73         page = cherrypy._cperror.get_error_page(status, message=message)
74        
75         # First, test the response body without checking the traceback.
76         # Stick a match-all group (.*) in to grab the traceback.
77         esc = re.escape
78         epage = esc(page)
79         epage = epage.replace(esc('<pre id="traceback"></pre>'),
80                               esc('<pre id="traceback">') + '(.*)' + esc('</pre>'))
81         m = re.match(epage, self.body, re.DOTALL)
82         if not m:
83             self._handlewebError('Error page does not match\n' + page)
84             return
85        
86         # Now test the pattern against the traceback
87         if pattern is None:
88             # Special-case None to mean that there should be *no* traceback.
89             if m and m.group(1):
90                 self._handlewebError('Error page contains traceback')
91         else:
92             if (m is None) or (not re.search(re.escape(pattern), m.group(1))):
93                 msg = 'Error page does not contain %s in traceback'
94                 self._handlewebError(msg % repr(pattern))
95
96
97 CPTestLoader = webtest.ReloadingTestLoader()
98 CPTestRunner = webtest.TerseTestRunner(verbosity=2)
99
100 def setConfig(conf):
101     """Set the global config using a copy of conf."""
102     if isinstance(conf, basestring):
103         # assume it's a filename
104         cherrypy.config.update(conf)
105     else:
106         cherrypy.config.update(conf.copy())
107
108
109 def run_test_suite(moduleNames, server, conf):
110     """Run the given test modules using the given server and conf.
111     
112     The server is started and stopped once, regardless of the number
113     of test modules. The config, however, is reset for each module.
114     """
115     cherrypy.config.reset()
116     setConfig(conf)
117     cherrypy.server.quickstart(server)
118     # The Pybots automatic testing system needs the suite to exit
119     # with a non-zero value if there were any problems.
120     # Might as well stick it in the engine... :/
121     cherrypy.engine.test_success = True
122     cherrypy.engine.start_with_callback(_run_test_suite_thread,
123                                         args=(moduleNames, conf))
124     if cherrypy.engine.test_success:
125         return 0
126     else:
127         return 1
128
129 def sync_apps(profile=False, validate=False, conquer=False):
130     apps = []
131     for base, app in cherrypy.tree.apps.iteritems():
132         if base == "/":
133             base = ""
134         if profile:
135             app = profiler.make_app(app, aggregate=False)
136         if conquer:
137             try:
138                 import wsgiconq
139             except ImportError:
140                 warnings.warn("Error importing wsgiconq. pyconquer will not run.")
141             else:
142                 app = wsgiconq.WSGILogger(app)
143         if validate:
144             try:
145                 from wsgiref import validate
146             except ImportError:
147                 warnings.warn("Error importing wsgiref. The validator will not run.")
148             else:
149                 app = validate.validator(app)
150         apps.append((base, app))
151     apps.sort()
152     apps.reverse()
153     for s in cherrypy.server.httpservers:
154         s.mount_points = apps
155
156 def _run_test_suite_thread(moduleNames, conf):
157     for testmod in moduleNames:
158         # Must run each module in a separate suite,
159         # because each module uses/overwrites cherrypy globals.
160         cherrypy.tree = cherrypy._cptree.Tree()
161         cherrypy.config.reset()
162         setConfig(conf)
163        
164         m = __import__(testmod, globals(), locals())
165         setup = getattr(m, "setup_server", None)
166         if setup:
167             setup()
168        
169         # The setup functions probably mounted new apps.
170         # Tell our server about them.
171         sync_apps(profile=conf.get("profiling.on", False),
172                   validate=conf.get("validator.on", False),
173                   conquer=conf.get("conquer.on", False),
174                   )
175        
176         suite = CPTestLoader.loadTestsFromName(testmod)
177         result = CPTestRunner.run(suite)
178         cherrypy.engine.test_success &= result.wasSuccessful()
179        
180         teardown = getattr(m, "teardown_server", None)
181         if teardown:
182             teardown()
183     thread.interrupt_main()
184
185 def testmain(conf=None):
186     """Run __main__ as a test module, with webtest debugging."""
187     if conf is None:
188         conf = {'server.socket_host': '127.0.0.1'}
189     setConfig(conf)
190     try:
191         cherrypy.server.quickstart()
192         cherrypy.engine.start_with_callback(_test_main_thread)
193     except KeyboardInterrupt:
194         cherrypy.server.stop()
195         cherrypy.engine.stop()
196
197 def _test_main_thread():
198     try:
199         webtest.WebCase.PORT = cherrypy.server.socket_port
200         webtest.main()
201     finally:
202         thread.interrupt_main()
203
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets