def test_setting_file_for_download_includes_a_content_length_header(self): response = Response() with NamedTemporaryFile() as tmpfile: tmpfile.write(b'foobar') tmpfile.seek(0) response.file(tmpfile.name, download=True, name='image.png') self.assertEqual(response.headers['Content-Length'], '6')
def test_setting_file_for_download(self): response = Response() with NamedTemporaryFile() as tmpfile: response.file(tmpfile.name, download=True) filename = os.path.basename(tmpfile.name) self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename="{}"'.format(filename))
def test_setting_file_without_extension_changes_content_type_to_octet_stream( self): response = Response() with NamedTemporaryFile() as tmpfile: response.file(tmpfile.name) self.assertEqual(response.headers['Content-Type'], 'application/octet-stream')
def test_set_cookie_with_expires_date(self): response = Response() response.set_cookie('token', 'abc', expires=datetime(2017, 4, 9, 10, 35, 54)) expected_cookie = 'token=abc; Expires=Sun, 09 Apr 2017 10:35:54 GMT; HttpOnly; SameSite=Strict' self.assertIn(('Set-Cookie', expected_cookie), response._wsgi_headers())
def test_setting_file_without_name_puts_the_path_filename_in_the_header( self): response = Response() with NamedTemporaryFile(suffix='.png') as tmpfile: response.file(tmpfile.name) filename = os.path.basename(tmpfile.name) self.assertEqual(response.headers['Content-Disposition'], 'inline; filename="{}"'.format(filename))
def test_file_gets_returned_as_generator_to_wsgi(self): response = Response() with NamedTemporaryFile() as tmpfile: tmpfile.write(b'hello world') tmpfile.seek(0) response.file(tmpfile.name) start_respose = Mock() self.assertIsInstance(response.wsgi(start_respose), GeneratorType)
def test_submit_on_sub_node_might_replace_response_returning_another_one( self): root, node = Node(), Node() root.link(node) node.handle = Mock(return_value=Response()) request = Request({}) original_response = Response() response = root.submit(request, original_response) self.assertIsNot(response, original_response)
def test_wsgi_for_filled_response(self): response = Response() response.status = 400 response.headers['Content-Type'] = 'application/json' response.body = b'{"error": "Invalid token"}' expected_status = '400 Bad Request' expected_headers = {'Content-Type': 'application/json'} expected_body = b'{"error": "Invalid token"}' self.assert_response(response, expected_status, expected_headers, expected_body)
def test_set_cookie_with_all_attributes(self): response = Response() response.set_cookie('token', 'abc', expires=datetime(2017, 4, 9, 10, 35, 54), domain='my.domain.com', path='/foo', secure=True) expected_cookie = 'token=abc; Expires=Sun, 09 Apr 2017 10:35:54 GMT; Domain=my.domain.com; Path=/foo; Secure; HttpOnly; SameSite=Strict' self.assertIn(('Set-Cookie', expected_cookie), response._wsgi_headers())
def test_submit_recurses_through_sub_nodes(self): root, a, b = Node(), Node(), Node() root.link(a) a.link(b) root.handle = Mock(return_value=Response()) a.handle = Mock(return_value=Response()) b.handle = Mock(return_value=Response()) request = Request({}) root.submit(request) self.assertEqual(root.handle.call_count, 1) self.assertEqual(a.handle.call_count, 1) self.assertEqual(b.handle.call_count, 1)
def test_all_file_contents_are_yielded_by_its_generator(self): response = Response() with NamedTemporaryFile() as tmpfile: tmpfile.write(b'hello world') tmpfile.seek(0) response.file(tmpfile.name) start_respose = Mock() file_generator = response.wsgi(start_respose) contents = b'' for chunk in file_generator: contents += chunk self.assertEqual(contents, b'hello world')
def test_node_handle_can_raise_response_instead_of_returning(self): node = Node() handle_response = Response() node.handle = Mock(side_effect=handle_response) request = Request({}) response = node.submit(request) self.assertIs(response, handle_response)
def test_wsgi_for_empty_response(self): response = Response() expected_status = '404 Not Found' expected_headers = {} expected_body = b'' self.assert_response(response, expected_status, expected_headers, expected_body)
def test_raised_response_is_not_catched_by_default_exception_handler(self): response = Response() with self.assertRaises(Response): try: raise response except Exception: pass
def test_returned_response_can_be_altered_by_handle_return(self): node = Node() handle_response = Response() node.handle = Mock(return_value=handle_response) request = Request({}) response = node.submit(request) self.assertIs(response, handle_response)
def test_sub_nodes_are_not_called_if_response_is_raised_from_node_handle( self): root, node = Node(), Node() root.link(node) root.handle = Mock(side_effect=Response()) node.submit = Mock() request = Request({}) root.submit(request) self.assertEqual(node.submit.call_count, 0)
def test_submitted_response_stays_the_same_if_not_changed_by_the_node_recursion( self): root, a, b = Node(), Node(), Node() root.link(a) a.link(b) request = Request({}) original_response = Response() response = root.submit(request, original_response) self.assertIs(response, original_response)
def test_set_two_cookies(self): response = Response() response.set_cookie('token1', 'abc') response.set_cookie('token2', 'xyz') expected_cookie1 = 'token1=abc; HttpOnly; SameSite=Strict' expected_cookie2 = 'token2=xyz; HttpOnly; SameSite=Strict' self.assertIn(('Set-Cookie', expected_cookie1), response._wsgi_headers()) self.assertIn(('Set-Cookie', expected_cookie2), response._wsgi_headers())
def test_submit_can_be_called_with_previously_created_response(self): node = Node() request = Request({}) original_response = Response() response = node.submit(request, original_response) self.assertIs(response, original_response)
def test_node_handle_accepts_request_and_response(self): node = Node() request = Request({}) response = Response() node_response = node.handle(request, response) self.assertIs(node_response, response)
def test_unset_cookie(self): response = Response() response.unset_cookie('token') expected_cookie = 'token=; Expires=Thu, 01 Jan 1970 00:00:00 GMT' self.assertIn(('Set-Cookie', expected_cookie), response._wsgi_headers())
def test_response_object_can_be_raised(self): response = Response() with self.assertRaises(Response): raise response
def test_setting_body_converts_any_object_into_its_string_representation( self): response = Response() response.body = {'foo': 'bar'} self.assertEqual(response.body, b"{'foo': 'bar'}")
def test_can_concatenate_bytes_to_previously_set_body_string(self): response = Response() response.body = 'hello' response.body += b' world' self.assertEqual(response.body, b'hello world')
def test_unset_cookie_with_domain_and_path(self): response = Response() response.unset_cookie('token', domain='my.domain.com', path='/foo') expected_cookie = 'token=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Domain=my.domain.com; Path=/foo' self.assertIn(('Set-Cookie', expected_cookie), response._wsgi_headers())
def test_submit_calls_node_handle(self): node = Node() node.handle = Mock(return_value=Response()) request = Request({}) response = node.submit(request) self.assertEqual(node.handle.call_count, 1)
def test_special_characters_in_cookie_value_get_escaped(self): response = Response() response.set_cookie('token', 'abc/;,~รกรง[\'!""]') expected_cookie = 'token="abc/\\073\\054~\\341\\347[\'!\\"\\"]"; HttpOnly; SameSite=Strict' self.assertIn(('Set-Cookie', expected_cookie), response._wsgi_headers())
def test_string_body_gets_converted_to_bytes(self): response = Response() response.body = 'hello world' self.assertEqual(response._wsgi_body(), (b'hello world', ))
def test_header_keys_are_case_insensitive(self): response = Response() response.headers['foo'] = 'bar' self.assertEqual(response.headers['FOO'], 'bar')
def test_illegal_character_in_cookie_key_triggers_exception(self): response = Response() with self.assertRaises(CookieError): response.set_cookie('token;', 'abc')