cubicweb/devtools/httptest.py
changeset 11158 669eac69ea21
parent 11057 0b59724cb3f2
child 11160 ed048bfd1b88
equal deleted inserted replaced
11157:42fa15632493 11158:669eac69ea21
    60         finally:
    60         finally:
    61             s.close()
    61             s.close()
    62     raise RuntimeError('get_available_port([ports_range]) cannot find an available port')
    62     raise RuntimeError('get_available_port([ports_range]) cannot find an available port')
    63 
    63 
    64 
    64 
    65 class CubicWebServerTC(CubicWebTC):
    65 class _CubicWebServerTC(CubicWebTC):
    66     """Class for running a Twisted-based test web server.
    66     """Class for running a Twisted-based test web server.
    67     """
    67     """
    68     ports_range = range(7000, 8000)
    68     ports_range = range(7000, 8000)
    69 
    69 
       
    70     def start_server(self):
       
    71         raise NotImplementedError
       
    72 
       
    73     def stop_server(self, timeout=15):
       
    74         """Stop the webserver, waiting for the thread to return"""
       
    75         raise NotImplementedError
       
    76 
       
    77     def web_login(self, user=None, passwd=None):
       
    78         """Log the current http session for the provided credential
       
    79 
       
    80         If no user is provided, admin connection are used.
       
    81         """
       
    82         if user is None:
       
    83             user  = self.admlogin
       
    84             passwd = self.admpassword
       
    85         if passwd is None:
       
    86             passwd = user
       
    87         response = self.web_get("login?__login=%s&__password=%s" %
       
    88                                 (user, passwd))
       
    89         assert response.status == http_client.SEE_OTHER, response.status
       
    90         self._ident_cookie = response.getheader('Set-Cookie')
       
    91         assert self._ident_cookie
       
    92         return True
       
    93 
       
    94     def web_logout(self, user='admin', pwd=None):
       
    95         """Log out current http user"""
       
    96         if self._ident_cookie is not None:
       
    97             response = self.web_get('logout')
       
    98         self._ident_cookie = None
       
    99 
       
   100     def web_request(self, path='', method='GET', body=None, headers=None):
       
   101         """Return an http_client.HTTPResponse object for the specified path
       
   102 
       
   103         Use available credential if available.
       
   104         """
       
   105         if headers is None:
       
   106             headers = {}
       
   107         if self._ident_cookie is not None:
       
   108             assert 'Cookie' not in headers
       
   109             headers['Cookie'] = self._ident_cookie
       
   110         self._web_test_cnx.request(method, '/' + path, headers=headers, body=body)
       
   111         response = self._web_test_cnx.getresponse()
       
   112         response.body = response.read() # to chain request
       
   113         response.read = lambda : response.body
       
   114         return response
       
   115 
       
   116     def web_get(self, path='', body=None, headers=None):
       
   117         return self.web_request(path=path, body=body, headers=headers)
       
   118 
       
   119     def setUp(self):
       
   120         super(_CubicWebServerTC, self).setUp()
       
   121         port = self.config['port'] or get_available_port(self.ports_range)
       
   122         self.config.global_set_option('port', port) # force rewrite here
       
   123         self.config.global_set_option('base-url', 'http://127.0.0.1:%d/' % port)
       
   124         # call load_configuration again to let the config reset its datadir_url
       
   125         self.config.load_configuration()
       
   126         self.start_server()
       
   127 
       
   128     def tearDown(self):
       
   129         self.stop_server()
       
   130         super(_CubicWebServerTC, self).tearDown()
       
   131 
       
   132 
       
   133 class CubicWebServerTC(_CubicWebServerTC):
    70     def start_server(self):
   134     def start_server(self):
    71         from twisted.internet import reactor
   135         from twisted.internet import reactor
    72         from cubicweb.etwist.server import run
   136         from cubicweb.etwist.server import run
    73         # use a semaphore to avoid starting test while the http server isn't
   137         # use a semaphore to avoid starting test while the http server isn't
    74         # fully initilialized
   138         # fully initilialized
   107             assert not self.web_thread.isAlive()
   171             assert not self.web_thread.isAlive()
   108 
   172 
   109         finally:
   173         finally:
   110             reactor.__init__()
   174             reactor.__init__()
   111 
   175 
   112     def web_login(self, user=None, passwd=None):
   176 
   113         """Log the current http session for the provided credential
   177 class CubicWebWsgiTC(CubicWebServerTC):
   114 
   178     def start_server(self):
   115         If no user is provided, admin connection are used.
   179         from cubicweb.wsgi.handler import CubicWebWSGIApplication
   116         """
   180         from wsgiref import simple_server
   117         if user is None:
   181         from six.moves import queue
   118             user  = self.admlogin
   182 
   119             passwd = self.admpassword
   183         config = self.config
   120         if passwd is None:
   184         port = config['port'] or 8080
   121             passwd = user
   185         interface = config['interface']
   122         response = self.web_get("login?__login=%s&__password=%s" %
   186         handler_cls = simple_server.WSGIRequestHandler
   123                                 (user, passwd))
   187         app = CubicWebWSGIApplication(config)
   124         assert response.status == http_client.SEE_OTHER, response.status
   188         start_flag = queue.Queue()
   125         self._ident_cookie = response.getheader('Set-Cookie')
   189 
   126         assert self._ident_cookie
   190         def run(config, *args, **kwargs):
   127         return True
   191             try:
   128 
   192                 self.httpd = simple_server.WSGIServer((interface, port), handler_cls)
   129     def web_logout(self, user='admin', pwd=None):
   193                 self.httpd.set_app(app)
   130         """Log out current http user"""
   194             except Exception as exc:
   131         if self._ident_cookie is not None:
   195                 start_flag.put(False)
   132             response = self.web_get('logout')
   196                 start_flag.put(exc)
       
   197                 raise
       
   198             else:
       
   199                 start_flag.put(True)
       
   200             try:
       
   201                 self.httpd.serve_forever()
       
   202             finally:
       
   203                 self.httpd.server_close()
       
   204         t = threading.Thread(target=run, name='cubicweb_test_web_server',
       
   205                              args=(self.config, True), kwargs={'repo': self.repo})
       
   206         self.web_thread = t
       
   207         t.start()
       
   208         flag = start_flag.get()
       
   209         if not flag:
       
   210             t.join()
       
   211             self.fail(start_flag.get())
       
   212         parseurl = urlparse(self.config['base-url'])
       
   213         assert parseurl.port == self.config['port'], (self.config['base-url'], self.config['port'])
       
   214         self._web_test_cnx = http_client.HTTPConnection(parseurl.hostname,
       
   215                                                         parseurl.port)
   133         self._ident_cookie = None
   216         self._ident_cookie = None
   134 
   217 
   135     def web_request(self, path='', method='GET', body=None, headers=None):
   218     def stop_server(self, timeout=15):
   136         """Return an http_client.HTTPResponse object for the specified path
   219         if self._web_test_cnx is None:
   137 
   220             self.web_logout()
   138         Use available credential if available.
   221             self._web_test_cnx.close()
   139         """
   222         self.httpd.shutdown()
   140         if headers is None:
   223         self.web_thread.join(timeout)
   141             headers = {}
       
   142         if self._ident_cookie is not None:
       
   143             assert 'Cookie' not in headers
       
   144             headers['Cookie'] = self._ident_cookie
       
   145         self._web_test_cnx.request(method, '/' + path, headers=headers, body=body)
       
   146         response = self._web_test_cnx.getresponse()
       
   147         response.body = response.read() # to chain request
       
   148         response.read = lambda : response.body
       
   149         return response
       
   150 
       
   151     def web_get(self, path='', body=None, headers=None):
       
   152         return self.web_request(path=path, body=body, headers=headers)
       
   153 
       
   154     def setUp(self):
       
   155         super(CubicWebServerTC, self).setUp()
       
   156         port = self.config['port'] or get_available_port(self.ports_range)
       
   157         self.config.global_set_option('port', port) # force rewrite here
       
   158         self.config.global_set_option('base-url', 'http://127.0.0.1:%d/' % port)
       
   159         # call load_configuration again to let the config reset its datadir_url
       
   160         self.config.load_configuration()
       
   161         self.start_server()
       
   162 
       
   163     def tearDown(self):
       
   164         from twisted.internet import error
       
   165         try:
       
   166             self.stop_server()
       
   167         except error.ReactorNotRunning as err:
       
   168             # Server could be launched manually
       
   169             print(err)
       
   170         super(CubicWebServerTC, self).tearDown()