23 __docformat__ = "restructuredtext en" |
23 __docformat__ = "restructuredtext en" |
24 |
24 |
25 import threading |
25 import threading |
26 import socket |
26 import socket |
27 import httplib |
27 import httplib |
|
28 from urlparse import urlparse |
28 |
29 |
29 from twisted.internet import reactor, error |
30 from twisted.internet import reactor, error |
30 |
31 |
31 from cubicweb.etwist.server import run |
32 from cubicweb.etwist.server import run |
32 from cubicweb.devtools.testlib import CubicWebTC |
33 from cubicweb.devtools.testlib import CubicWebTC |
|
34 from cubicweb.devtools import ApptestConfiguration |
33 |
35 |
34 |
36 |
35 def get_available_port(ports_scan): |
37 def get_available_port(ports_scan): |
36 """return the first available port from the given ports range |
38 """return the first available port from the given ports range |
37 |
39 |
41 Raise a RuntimeError if no port can be found |
43 Raise a RuntimeError if no port can be found |
42 |
44 |
43 :type ports_range: list |
45 :type ports_range: list |
44 :param ports_range: range of ports to test |
46 :param ports_range: range of ports to test |
45 :rtype: int |
47 :rtype: int |
|
48 |
|
49 .. see:: :func:`test.test_support.bind_port` |
46 """ |
50 """ |
47 for port in ports_scan: |
51 for port in ports_scan: |
48 try: |
52 try: |
49 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
53 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
50 sock = s.connect(("localhost", port)) |
54 sock = s.connect(("localhost", port)) |
54 finally: |
58 finally: |
55 s.close() |
59 s.close() |
56 raise RuntimeError('get_available_port([ports_range]) cannot find an available port') |
60 raise RuntimeError('get_available_port([ports_range]) cannot find an available port') |
57 |
61 |
58 |
62 |
59 class CubicWebServerTC(CubicWebTC): |
63 class CubicWebServerConfig(ApptestConfiguration): |
60 """basic class for running test server |
64 """basic configuration class for configuring test server |
61 |
65 |
62 :param ports_range: range of http ports to test (range(7000, 8000) by default) |
66 :param ports_range: range of http ports to test (range(7000, 8000) by default) |
63 :type ports_range: iterable |
67 :type ports_range: iterable |
64 :param anonymous_logged: is anonymous user logged by default ? (True by default) |
68 :param anonymous_logged: is anonymous user logged by default ? (True by default) |
65 :type anonymous_logged: bool |
69 :type anonymous_logged: bool |
66 :param test_url: base url used by server |
70 :param port: server port (optional, used to force value) |
67 :param test_host: server host |
71 :type port: int |
68 :param test_port: server port |
|
69 |
72 |
70 The first port found as available in `ports_range` will be used to launch |
73 The first port found as available in `ports_range` will be used to launch |
71 the test server |
74 the test server |
72 """ |
75 """ |
73 ports_range = range(7000, 8000) |
|
74 # anonymous is logged by default in cubicweb test cases |
76 # anonymous is logged by default in cubicweb test cases |
75 anonymous_logged = True |
77 anonymous_logged = True |
76 test_host='127.0.0.1' |
78 ports_range = range(7000, 8000) |
|
79 |
|
80 def default_base_url(self): |
|
81 port = self['port'] or get_available_port(self.ports_range) |
|
82 self.global_set_option('port', port) # force rewrite here |
|
83 return 'http://127.0.0.1:%d/' % self['port'] |
|
84 |
|
85 def pyro_enabled(self): |
|
86 return False |
|
87 |
|
88 def load_configuration(self): |
|
89 super(CubicWebServerConfig, self).load_configuration() |
|
90 self.global_set_option('base-url', self.default_base_url()) |
|
91 if not self.anonymous_logged: |
|
92 self.global_set_option('anonymous-user', None) |
|
93 else: |
|
94 self.global_set_option('anonymous-user', 'anon') |
|
95 self.global_set_option('anonymous-password', 'anon') |
|
96 self.global_set_option('force-html-content-type', True) |
|
97 # no undo support in tests |
|
98 self.global_set_option('undo-support', '') |
77 |
99 |
78 |
100 |
|
101 class CubicWebServerTC(CubicWebTC): |
|
102 """class for running test server |
79 |
103 |
80 @property |
104 :cvar: :ref:`CubicWebServerConfig` class |
81 def test_url(self): |
105 """ |
82 return 'http://%s:%d/' % (self.test_host, self.test_port) |
106 configcls = CubicWebServerConfig |
83 |
|
84 def init_server(self): |
|
85 self.test_port = get_available_port(self.ports_range) |
|
86 self.config['port'] = self.test_port |
|
87 self.config['base-url'] = self.test_url |
|
88 self.config['force-html-content-type'] = True |
|
89 self.config['pyro-server'] = False |
|
90 |
107 |
91 def start_server(self): |
108 def start_server(self): |
92 self.config.pyro_enabled = lambda : False |
|
93 # use a semaphore to avoid starting test while the http server isn't |
109 # use a semaphore to avoid starting test while the http server isn't |
94 # fully initilialized |
110 # fully initilialized |
95 semaphore = threading.Semaphore(0) |
111 semaphore = threading.Semaphore(0) |
96 def safe_run(*args, **kwargs): |
112 def safe_run(*args, **kwargs): |
97 try: |
113 try: |
101 |
117 |
102 reactor.addSystemEventTrigger('after', 'startup', semaphore.release) |
118 reactor.addSystemEventTrigger('after', 'startup', semaphore.release) |
103 t = threading.Thread(target=safe_run, name='cubicweb_test_web_server', |
119 t = threading.Thread(target=safe_run, name='cubicweb_test_web_server', |
104 args=(self.config, self.vreg, True)) |
120 args=(self.config, self.vreg, True)) |
105 self.web_thread = t |
121 self.web_thread = t |
106 if not self.anonymous_logged: |
|
107 self.config.global_set_option('anonymous-user', None) |
|
108 t.start() |
122 t.start() |
109 semaphore.acquire() |
123 semaphore.acquire() |
110 if not self.web_thread.isAlive(): |
124 if not self.web_thread.isAlive(): |
111 # XXX race condition with actual thread death |
125 # XXX race condition with actual thread death |
112 raise RuntimeError('Could not start the web server') |
126 raise RuntimeError('Could not start the web server') |
113 #pre init utils connection |
127 #pre init utils connection |
114 self._web_test_cnx = httplib.HTTPConnection(self.test_host, self.test_port) |
128 parseurl = urlparse(self.config['base-url']) |
|
129 assert parseurl.port == self.config['port'] |
|
130 self._web_test_cnx = httplib.HTTPConnection(parseurl.hostname, |
|
131 parseurl.port) |
115 self._ident_cookie = None |
132 self._ident_cookie = None |
116 |
133 |
117 def stop_server(self, timeout=15): |
134 def stop_server(self, timeout=15): |
118 """Stop the webserver, waiting for the thread to return""" |
135 """Stop the webserver, waiting for the thread to return""" |
119 if self._web_test_cnx is None: |
136 if self._web_test_cnx is None: |