def test_results_can_be_retrieved(self): payload = { "name": "test has results", "setup": "pass", "snippets": ("pass", "pass") } start_response = StartResponseMock() result = self.app( create_environ( path='/entries', method='POST', body=json.dumps(payload), ), start_response, )[0].decode() result = json.loads(result) start_response2 = StartResponseMock() result2 = self.app( create_environ(path='/entries/{0}/results'.format(result['id']), ), start_response2, )[0].decode() result2 = json.loads(result2) self.assertTrue(start_response2.status != '404 Not Found') self.assertTrue(start_response2.status != '500 Internal Server Error') for snippet in result2['snippets']: self.assertTrue(snippet['runtime'] is None) self.assertTrue(snippet['memory']['max'] is None) self.assertTrue(snippet['memory']['avg'] is None) self.assertTrue(snippet['memory']['min'] is None)
def test_create_can_be_retrieved_later(self): payload = { "name": "test can be retrieved", "setup": "pass", "snippets": ("pass", "pass") } start_response = StartResponseMock() result = self.app( create_environ( path='/entries', method='POST', body=json.dumps(payload), ), start_response, )[0].decode() result = json.loads(result) start_response2 = StartResponseMock() result2 = self.app( create_environ(path='/entries/{0}'.format(result['id']), ), start_response2, )[0].decode() result2 = json.loads(result2) self.assertTrue(start_response2.status != '404 Not Found') self.assertTrue(result2['id'] == result['id']) self.assertTrue(result2['name'] == payload['name']) self.assertTrue(result2['setup'] == payload['setup']) for snip1, snip2 in zip(payload['snippets'], result2['snippets']): self.assertTrue(snip1 == snip2)
def simulate_request(self, method='GET', path='/', query_string=None, headers=None, body=None, file_wrapper=None): """Simulates a request to a WSGI application. Performs a WSGI request directly against ``self.api``. Keyword Args: method (str): The HTTP method to use in the request (default: 'GET') path (str): The URL path to request (default: '/') query_string (str): A raw query string to include in the request (default: ``None``) headers (dict): Additional headers to include in the request (default: ``None``) body (str): A string to send as the body of the request. Accepts both byte strings and Unicode strings (default: ``None``). If a Unicode string is provided, it will be encoded as UTF-8 in the request. file_wrapper (callable): Callable that returns an iterable, to be used as the value for *wsgi.file_wrapper* in the environ (default: ``None``). Returns: :py:class:`~.Result`: The result of the request """ if not path.startswith('/'): raise ValueError("path must start with '/'") if query_string and query_string.startswith('?'): raise ValueError("query_string should not start with '?'") if '?' in path: # NOTE(kgriffs): We could allow this, but then we'd need # to define semantics regarding whether the path takes # precedence over the query_string. Also, it would make # tests less consistent, since there would be "more than # one...way to do it." raise ValueError( 'path may not contain a query string. Please use the ' 'query_string parameter instead.' ) env = create_environ( method=method, path=path, query_string=(query_string or ''), headers=headers, body=body, file_wrapper=file_wrapper, ) srmock = StartResponseMock() validator = wsgiref.validate.validator(self.api) iterable = validator(env, srmock) result = Result(iterable, srmock.status, srmock.headers) return result
def fake_request(self, path, **kwargs): kwargs.setdefault("headers", {}) content_type = kwargs.pop("content_type", None) if content_type: kwargs["headers"]["Content-Type"] = content_type if self._before: self._before(kwargs) parsed = urlparse(path) path = parsed.path if parsed.query: kwargs["query_string"] = parsed.query if isinstance(kwargs.get("query_string", None), dict): kwargs["query_string"] = urlencode(kwargs["query_string"]) self.encode_body(kwargs) resp = StartResponseMock() environ = create_environ(path, **kwargs) resp.environ = environ body = self.app(environ, resp) resp.headers = resp.headers_dict resp.status_code = int(resp.status.split(" ")[0]) resp.body = b"".join(list(body)) if body else b"" try: # …to be smart and provide the response as str if it let iself # decode. resp.body = resp.body.decode() except UnicodeDecodeError: # But do not insist. pass if "application/json" in resp.headers.get("Content-Type", ""): resp.json = json.loads(resp.body) if resp.body else {} if self._after: self._after(resp) return resp
def fake_request(self, path, **kwargs): kwargs.setdefault('headers', {}) content_type = kwargs.pop('content_type', None) if content_type: kwargs['headers']['Content-Type'] = content_type if self._before: self._before(kwargs) parsed = urlparse(path) path = parsed.path if parsed.query: kwargs['query_string'] = parsed.query if isinstance(kwargs.get('query_string', None), dict): kwargs['query_string'] = urlencode(kwargs['query_string']) self.encode_body(kwargs) resp = StartResponseMock() body = self.app(create_environ(path, **kwargs), resp) resp.headers = resp.headers_dict resp.status_code = int(resp.status.split(' ')[0]) resp.body = b''.join(list(body)) if body else b'' try: # …to be smart and provide the response as str if it let iself # decode. resp.body = resp.body.decode() except UnicodeDecodeError: # But do not insist. pass if 'application/json' in resp.headers.get('Content-Type', ''): resp.json = json.loads(resp.body) if resp.body else {} if self._after: self._after(resp) return resp
def setUp(self): """Initializer, unittest-style""" super(TestBase, self).setUp() self.api = falcon.API() self.srmock = StartResponseMock() self.test_route = '/' + self.getUniqueString() before = getattr(self, 'before', None) if hasattr(before, '__call__'): before()
def setUp(self): """Initializer, unittest-style""" super(TestBase, self).setUp() self._id = itertools.count(0) self.api = falcon.API() self.srmock = StartResponseMock() self.test_route = '/{0}'.format(next(self._id)) before = getattr(self, 'before', None) if hasattr(before, '__call__'): before()
def test_create_errors_when_payload_invalid(self): start_response = StartResponseMock() self.app( create_environ( path='/entries', method='POST', body='{"name": "test"}', # Missing values ), start_response, )[0].decode() self.assertTrue(start_response.status == '400 Bad Request')
def test_create_errors_when_json_invalid(self): start_response = StartResponseMock() self.app( create_environ( path='/entries', method='POST', body='{{[[[}}]', ), start_response, )[0].decode() self.assertTrue(start_response.status == '400 Bad Request')
def setUp(self): """Initializer, unittest-style""" super(TestBase, self).setUp() self._id = itertools.count(0) self.api = falcon.API() self.srmock = StartResponseMock() self.test_route = '/{0}'.format(next(self._id)) # Reset to simulate "restarting" the WSGI container falcon.request._maybe_wrap_wsgi_stream = True before = getattr(self, 'before', None) if callable(before): before()
def test_can_list_all_entries(self): results = self.app( create_environ(path='/entries', ), StartResponseMock(), )[0].decode() results = json.loads(results) try: for r in results: pass except TypeError: raise AssertionError('API results are not iterable.')
def test_create_succeeds_when_payload_correct(self): start_response = StartResponseMock() result = self.app( create_environ( path='/entries', method='POST', body=json.dumps({ "name": "test correct payload", "setup": "pass", "snippets": ("pass", "pass") }), ), start_response, )[0].decode() result = json.loads(result) self.assertTrue(start_response.status == '201 Created') self.assertTrue(result['id'] == 'test_correct_payload')
def simulate_request(app, method='GET', path='/', query_string=None, headers=None, body=None, file_wrapper=None, wsgierrors=None, params=None, params_csv=True, protocol='http'): """Simulates a request to a WSGI application. Performs a request against a WSGI application. Uses :any:`wsgiref.validate` to ensure the response is valid WSGI. Keyword Args: app (callable): The WSGI application to call method (str): An HTTP method to use in the request (default: 'GET') path (str): The URL path to request (default: '/') protocol: The protocol to use for the URL scheme (default: 'http') params (dict): A dictionary of query string parameters, where each key is a parameter name, and each value is either a ``str`` or something that can be converted into a ``str``, or a list of such values. If a ``list``, the value will be converted to a comma-delimited string of values (e.g., 'thing=1,2,3'). params_csv (bool): Set to ``False`` to encode list values in query string params by specifying multiple instances of the parameter (e.g., 'thing=1&thing=2&thing=3'). Otherwise, parameters will be encoded as comma-separated values (e.g., 'thing=1,2,3'). Defaults to ``True``. query_string (str): A raw query string to include in the request (default: ``None``). If specified, overrides `params`. headers (dict): Additional headers to include in the request (default: ``None``) body (str): A string to send as the body of the request. Accepts both byte strings and Unicode strings (default: ``None``). If a Unicode string is provided, it will be encoded as UTF-8 in the request. file_wrapper (callable): Callable that returns an iterable, to be used as the value for *wsgi.file_wrapper* in the environ (default: ``None``). This can be used to test high-performance file transmission when `resp.stream` is set to a file-like object. wsgierrors (io): The stream to use as *wsgierrors* (default ``sys.stderr``) Returns: :py:class:`~.Result`: The result of the request """ if not path.startswith('/'): raise ValueError("path must start with '/'") if query_string and query_string.startswith('?'): raise ValueError("query_string should not start with '?'") if '?' in path: # NOTE(kgriffs): We could allow this, but then we'd need # to define semantics regarding whether the path takes # precedence over the query_string. Also, it would make # tests less consistent, since there would be "more than # one...way to do it." raise ValueError( 'path may not contain a query string. Please use the ' 'query_string parameter instead.' ) if query_string is None: query_string = to_query_str( params, comma_delimited_lists=params_csv, prefix=False, ) env = helpers.create_environ( method=method, scheme=protocol, path=path, query_string=(query_string or ''), headers=headers, body=body, file_wrapper=file_wrapper, wsgierrors=wsgierrors, ) srmock = StartResponseMock() validator = wsgiref.validate.validator(app) iterable = validator(env, srmock) result = Result(iterable, srmock.status, srmock.headers) return result
def simulate_request(app, method='GET', path='/', query_string=None, headers=None, body=None, json=None, file_wrapper=None, wsgierrors=None, params=None, params_csv=True, protocol='http', host=helpers.DEFAULT_HOST, remote_addr=None, extras=None): """Simulates a request to a WSGI application. Performs a request against a WSGI application. Uses :any:`wsgiref.validate` to ensure the response is valid WSGI. Keyword Args: app (callable): The WSGI application to call method (str): An HTTP method to use in the request (default: 'GET') path (str): The URL path to request (default: '/'). Note: The path may contain a query string. However, neither `query_string` nor `params` may be specified in this case. protocol: The protocol to use for the URL scheme (default: 'http') params (dict): A dictionary of query string parameters, where each key is a parameter name, and each value is either a ``str`` or something that can be converted into a ``str``, or a list of such values. If a ``list``, the value will be converted to a comma-delimited string of values (e.g., 'thing=1,2,3'). params_csv (bool): Set to ``False`` to encode list values in query string params by specifying multiple instances of the parameter (e.g., 'thing=1&thing=2&thing=3'). Otherwise, parameters will be encoded as comma-separated values (e.g., 'thing=1,2,3'). Defaults to ``True``. query_string (str): A raw query string to include in the request (default: ``None``). If specified, overrides `params`. headers (dict): Additional headers to include in the request (default: ``None``) body (str): A string to send as the body of the request. Accepts both byte strings and Unicode strings (default: ``None``). If a Unicode string is provided, it will be encoded as UTF-8 in the request. json(JSON serializable): A JSON document to serialize as the body of the request (default: ``None``). If specified, overrides `body` and the Content-Type header in `headers`. file_wrapper (callable): Callable that returns an iterable, to be used as the value for *wsgi.file_wrapper* in the environ (default: ``None``). This can be used to test high-performance file transmission when `resp.stream` is set to a file-like object. host(str): A string to use for the hostname part of the fully qualified request URL (default: 'falconframework.org') remote_addr (str): A string to use as the remote IP address for the request (default: '127.0.0.1') wsgierrors (io): The stream to use as *wsgierrors* (default ``sys.stderr``) extras (dict): Additional CGI variables to add to the WSGI ``environ`` dictionary for the request (default: ``None``) Returns: :py:class:`~.Result`: The result of the request """ if not path.startswith('/'): raise ValueError("path must start with '/'") if '?' in path: if query_string or params: raise ValueError( 'path may not contain a query string in combination with ' 'the query_string or params parameters. Please use only one ' 'way of specifying the query string.') path, query_string = path.split('?', 1) elif query_string and query_string.startswith('?'): raise ValueError("query_string should not start with '?'") extras = extras or {} if 'REQUEST_METHOD' in extras and extras['REQUEST_METHOD'] != method: # NOTE(vytas): Even given the duct tape nature of overriding # arbitrary environ variables, changing the method can potentially # be very confusing, particularly when using specialized # simulate_get/post/patch etc methods. raise ValueError( 'environ extras may not override the request method. Please ' 'use the method parameter.') if query_string is None: query_string = to_query_str( params, comma_delimited_lists=params_csv, prefix=False, ) if json is not None: body = util_json.dumps(json, ensure_ascii=False) headers = headers or {} headers['Content-Type'] = MEDIA_JSON env = helpers.create_environ( method=method, scheme=protocol, path=path, query_string=(query_string or ''), headers=headers, body=body, file_wrapper=file_wrapper, host=host, remote_addr=remote_addr, wsgierrors=wsgierrors, ) if extras: env.update(extras) srmock = StartResponseMock() validator = wsgiref.validate.validator(app) iterable = validator(env, srmock) result = Result(helpers.closed_wsgi_iterable(iterable), srmock.status, srmock.headers) return result