class WsgidTest(unittest.TestCase): def setUp(self): self.wsgid = Wsgid() self.sample_headers = { 'METHOD': 'GET', 'VERSION': 'HTTP/1.1', 'PATTERN': '/root', 'URI': '/more/path/', 'PATH': '/more/path', 'QUERY': 'a=1&b=4&d=4', 'host': 'localhost', 'content-length': '42', 'content-type': 'text/plain', 'x-forwarded-for': '127.0.0.1' } sys.argv[1:] = [] parse_options() def tearDown(self): self.sample_headers = {} conf.settings = None ''' Creates the SCRIPT_NAME header from the mongrel2 PATTERN header. SCRIPT_NAME should be the PATTERN without any regex parts. ''' def test_script_name_header_simple_path(self): self.sample_headers['PATTERN'] = "/py" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/py", environ['SCRIPT_NAME']) def test_environ_script_name_header_more_comples_header(self): self.sample_headers['PATTERN'] = '/some/more/path/' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/more/path", environ['SCRIPT_NAME']) def test_environ_script_name_header_root(self): self.sample_headers['PATTERN'] = '/' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['SCRIPT_NAME']) ''' PATH_INFO comes from (URI - SCRIPT_NAME) or (PATH - SCRIPT_NAME) ''' def test_environ_path_info(self): self.sample_headers['PATTERN'] = '/py' self.sample_headers['PATH'] = '/py/some/py/path' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/py/path", environ['PATH_INFO']) def test_environ_path_info_app_root(self): self.sample_headers['PATTERN'] = '/py' self.sample_headers['PATH'] = '/py' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['PATH_INFO']) def test_environ_unquoted_path_info(self): self.sample_headers['PATTERN'] = '/py/' self.sample_headers['PATH'] = '/py/so%20me/special%3f/user%40path' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('/so me/special?/user@path', environ['PATH_INFO']) ''' Generates de REQUEST_METHOD variable ''' def test_environ_request_method(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key('REQUEST_METHOD')) self.assertEquals('GET', environ['REQUEST_METHOD']) def test_environ_query_string(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("a=1&b=4&d=4", environ['QUERY_STRING']) def test_environ_no_query_string(self): #Not always we have a QUERY_STRING del self.sample_headers['QUERY'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['QUERY_STRING']) def test_environ_server_port(self): self.sample_headers['host'] = 'localhost:443' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('443', environ['SERVER_PORT']) def test_environ_server_port_default_port(self): self.sample_headers['host'] = 'localhost' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('80', environ['SERVER_PORT']) def test_environ_server_name(self): self.sample_headers['host'] = 'localhost:8080' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost', environ['SERVER_NAME']) def test_environ_server_name_default_port(self): self.sample_headers['host'] = 'someserver' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('someserver', environ['SERVER_NAME']) ''' HTTP_HOST must inclue the port, if present. ''' def test_environ_http_host(self): self.sample_headers['host'] = 'localhost:8080' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost:8080', environ['HTTP_HOST']) def test_environ_content_type(self): self.sample_headers['content-type'] = 'application/xml' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('application/xml', environ['CONTENT_TYPE']) def test_environ_no_content_type(self): del self.sample_headers['content-type'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('', environ['CONTENT_TYPE']) def test_environ_content_length(self): self.sample_headers['content-length'] = '42' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('42', environ['CONTENT_LENGTH']) def test_environ_no_content_length(self): del self.sample_headers['content-length'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('', environ['CONTENT_LENGTH']) ''' Comes from mongrel2 VERSION header ''' def test_environ_server_protocol(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key('SERVER_PROTOCOL')) self.assertEquals('HTTP/1.1', environ['SERVER_PROTOCOL']) def test_eviron_remote_addr(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('127.0.0.1', environ['REMOTE_ADDR']) ''' Non Standard headers (X-) are passed untouched ''' def test_environ_non_standart_headers(self): self.sample_headers['X-Some-Header'] = 'some-value' self.sample_headers['x-other-header'] = 'other-value' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('some-value', environ['X-Some-Header']) self.assertEquals('other-value', environ['x-other-header']) def test_environ_http_host_header(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost', environ['HTTP_HOST']) ''' All headers (but HTTP common headers and X- headers) must be HTTP_ suffixed ''' def test_environ_other_headers(self): self.sample_headers['my_header'] = 'some-value' self.sample_headers['OTHER_HEADER'] = 'other-value' self.sample_headers['X-Some-Header'] = 'x-header' self.sample_headers['Accept'] = '*/*' self.sample_headers['Referer'] = 'http://www.someserver.com' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('some-value', environ['HTTP_MY_HEADER']) self.assertEquals('other-value', environ['HTTP_OTHER_HEADER']) self.assertEquals('x-header', environ['X-Some-Header']) self.assertEquals('*/*', environ['HTTP_ACCEPT']) self.assertEquals('http://www.someserver.com', environ['HTTP_REFERER']) ''' Test a complete request, with all typed of headers. ''' def test_eviron_complete_request(self): request = { 'METHOD': 'GET', 'VERSION': 'HTTP/1.1', 'PATTERN': '/py', 'URI': '/py/some/path', 'PATH': '/py/some/path', 'QUERY': 'a=1&b=4&d=4', 'host': 'localhost', 'Accept': '*/*', 'CUSTOM_HEADER': 'value', 'User-Agent': 'some user agent/1.0', 'content-length': '42', 'content-type': 'text/plain', 'x-forwarded-for': '127.0.0.1' } environ = self.wsgid._create_wsgi_environ(request) self.assertEquals(24, len(environ)) self.assertEquals('GET', environ['REQUEST_METHOD']) self.assertEquals('HTTP/1.1', environ['SERVER_PROTOCOL']) self.assertEquals('/py', environ['SCRIPT_NAME']) self.assertEquals('a=1&b=4&d=4', environ['QUERY_STRING']) self.assertEquals('/some/path', environ['PATH_INFO']) self.assertEquals('localhost', environ['SERVER_NAME']) self.assertEquals('80', environ['SERVER_PORT']) self.assertEquals('value', environ['HTTP_CUSTOM_HEADER']) self.assertEquals('*/*', environ['HTTP_ACCEPT']) self.assertEquals('some user agent/1.0', environ['HTTP_USER-AGENT']) self.assertEquals('42', environ['CONTENT_LENGTH']) self.assertEquals('42', environ['content-length']) self.assertEquals('text/plain', environ['CONTENT_TYPE']) self.assertEquals('text/plain', environ['content-type']) self.assertEquals('localhost', environ['HTTP_HOST']) self.assertEquals('127.0.0.1', environ['REMOTE_ADDR']) ''' Some values are fixed: * wsgi.multithread = False * wsgi.multiprocess = True * wsgi.run_once = True * wsgi.version = (1,0) ''' def test_environ_fixed_values(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals(False, environ['wsgi.multithread']) self.assertEquals(True, environ['wsgi.multiprocess']) self.assertEquals(True, environ['wsgi.run_once']) self.assertEquals((1,0), environ['wsgi.version']) self.assertEquals("http", environ['wsgi.url_scheme']) self.assertEquals(sys.stderr, environ['wsgi.errors']) def test_join_m2_chroot_to_async_upload_path(self): # The value in x-mongrel2-upload-{start,done} should be prepended with the # value of --m2-chroot, passed on the command line with patch('zmq.Context'): def _serve_request(wsgid, m2message, expected_final_path): with patch.object(wsgid, '_create_wsgi_environ'): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open") as mock_open: with patch('os.unlink'): wsgid._call_wsgi_app(message, Mock()) self.assertEquals(1, mock_open.call_count) mock_open.assert_called_with(expected_final_path) self._reparse_options('--mongrel2-chroot=/var/mongrel2') wsgid = Wsgid(app = Mock(return_value=['body response'])) message = self._create_fake_m2message('/uploads/m2.84Yet4') _serve_request(wsgid, message, '/var/mongrel2/uploads/m2.84Yet4') self._reparse_options() _serve_request(wsgid, message, '/uploads/m2.84Yet4') def test_remove_async_file_after_request_finishes_ok(self): # Since mongrel2 does not remove the originial temp file, wsgid # must remove it after the request was successfully (or not) handled. with patch('zmq.Context'): with patch('os.unlink') as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, '_create_wsgi_environ'): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app = Mock(return_value=['body response'])) message = self._create_fake_m2message('/uploads/m2.84Yet4') _serve_request(wsgid, message) mock_unlink.assert_called_with('/uploads/m2.84Yet4') def test_remove_async_file_after_failed_request(self): # Even if the request failed, wsgid must remove the temporary file. with patch('zmq.Context'): with patch('os.unlink') as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, '_create_wsgi_environ'): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app = Mock(side_effect = Exception("Failed"))) wsgid.log = Mock() message = self._create_fake_m2message('/uploads/m2.84Yet4') _serve_request(wsgid, message) mock_unlink.assert_called_with('/uploads/m2.84Yet4') def test_protect_against_exception_on_file_removal(self): with patch('zmq.Context'): with patch('os.unlink') as mock_unlink: mock_unlink.side_effect = OSError("File does not exist") def _serve_request(wsgid, m2message): with patch.object(wsgid, '_create_wsgi_environ'): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app = Mock(return_value = ['body response'])) wsgid.log = Mock() message = self._create_fake_m2message('/uploads/m2.84Yet4') _serve_request(wsgid, message) self.assertEquals(1, wsgid.log.exception.call_count) def test_do_not_try_to_remove_if_not_upload_request(self): with patch('zmq.Context'): with patch('os.unlink') as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, '_create_wsgi_environ'): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app = Mock(return_value = ['body response'])) wsgid.log = Mock() message = Mock() message.headers = [] #It's not an upload message message.client_id = 'uuid' message.server_id = '1' message.is_upload_done.return_value = False _serve_request(wsgid, message) self.assertEquals(0, mock_unlink.call_count) def _reparse_options(self, *args): sys.argv[1:] = args conf.settings = None parse_options() def _create_fake_m2message(self, async_upload_path): message = Mock() message.headers = {'x-mongrel2-upload-start': async_upload_path, 'x-mongrel2-upload-done': async_upload_path} message.async_upload_path = async_upload_path message.server_id = 'uuid' message.client_id = '42' return message
class WsgidTest(unittest.TestCase): def setUp(self): self.wsgid = Wsgid() self.sample_headers = { "METHOD": "GET", "VERSION": "HTTP/1.1", "PATTERN": "/root", "URI": "/more/path/", "PATH": "/more/path", "QUERY": "a=1&b=4&d=4", "host": "localhost", "content-length": "42", "content-type": "text/plain", "x-forwarded-for": "127.0.0.1", } sys.argv[1:] = [] parse_options() def tearDown(self): self.sample_headers = {} conf.settings = None """ Creates the SCRIPT_NAME header from the mongrel2 PATTERN header. SCRIPT_NAME should be the PATTERN without any regex parts. """ def test_script_name_header_simple_path(self): self.sample_headers["PATTERN"] = "/py" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/py", environ["SCRIPT_NAME"]) def test_environ_script_name_header_more_comples_header(self): self.sample_headers["PATTERN"] = "/some/more/path/" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/more/path", environ["SCRIPT_NAME"]) def test_environ_script_name_header_root(self): self.sample_headers["PATTERN"] = "/" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ["SCRIPT_NAME"]) """ PATH_INFO comes from (URI - SCRIPT_NAME) or (PATH - SCRIPT_NAME) """ def test_environ_path_info(self): self.sample_headers["PATTERN"] = "/py" self.sample_headers["PATH"] = "/py/some/py/path" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/py/path", environ["PATH_INFO"]) def test_environ_path_info_app_root(self): self.sample_headers["PATTERN"] = "/py" self.sample_headers["PATH"] = "/py" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ["PATH_INFO"]) def test_environ_unquoted_path_info(self): self.sample_headers["PATTERN"] = "/py/" self.sample_headers["PATH"] = "/py/so%20me/special%3f/user%40path" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/so me/special?/user@path", environ["PATH_INFO"]) """ Generates de REQUEST_METHOD variable """ def test_environ_request_method(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key("REQUEST_METHOD")) self.assertEquals("GET", environ["REQUEST_METHOD"]) def test_environ_query_string(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("a=1&b=4&d=4", environ["QUERY_STRING"]) def test_environ_no_query_string(self): # Not always we have a QUERY_STRING del self.sample_headers["QUERY"] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ["QUERY_STRING"]) def test_environ_server_port(self): self.sample_headers["host"] = "localhost:443" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("443", environ["SERVER_PORT"]) def test_environ_server_port_default_port(self): self.sample_headers["host"] = "localhost" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("80", environ["SERVER_PORT"]) def test_environ_server_name(self): self.sample_headers["host"] = "localhost:8080" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("localhost", environ["SERVER_NAME"]) def test_environ_server_name_default_port(self): self.sample_headers["host"] = "someserver" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("someserver", environ["SERVER_NAME"]) """ HTTP_HOST must inclue the port, if present. """ def test_environ_http_host(self): self.sample_headers["host"] = "localhost:8080" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("localhost:8080", environ["HTTP_HOST"]) def test_environ_content_type(self): self.sample_headers["content-type"] = "application/xml" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("application/xml", environ["CONTENT_TYPE"]) def test_environ_no_content_type(self): del self.sample_headers["content-type"] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ["CONTENT_TYPE"]) def test_environ_content_length(self): self.sample_headers["content-length"] = "42" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("42", environ["CONTENT_LENGTH"]) def test_environ_no_content_length(self): del self.sample_headers["content-length"] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ["CONTENT_LENGTH"]) """ Comes from mongrel2 VERSION header """ def test_environ_server_protocol(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key("SERVER_PROTOCOL")) self.assertEquals("HTTP/1.1", environ["SERVER_PROTOCOL"]) def test_eviron_remote_addr(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("127.0.0.1", environ["REMOTE_ADDR"]) """ Non Standard headers (X-) are passed untouched """ def test_environ_non_standart_headers(self): self.sample_headers["X-Some-Header"] = "some-value" self.sample_headers["x-other-header"] = "other-value" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("some-value", environ["HTTP_X_SOME_HEADER"]) self.assertEquals("other-value", environ["HTTP_X_OTHER_HEADER"]) def test_environ_http_host_header(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("localhost", environ["HTTP_HOST"]) """ All headers (but HTTP common headers and X- headers) must be HTTP_ suffixed """ def test_environ_other_headers(self): self.sample_headers["my_header"] = "some-value" self.sample_headers["OTHER_HEADER"] = "other-value" self.sample_headers["X-Some-Header"] = "x-header" self.sample_headers["Accept"] = "*/*" self.sample_headers["Referer"] = "http://www.someserver.com" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("some-value", environ["HTTP_MY_HEADER"]) self.assertEquals("other-value", environ["HTTP_OTHER_HEADER"]) self.assertEquals("x-header", environ["HTTP_X_SOME_HEADER"]) self.assertEquals("*/*", environ["HTTP_ACCEPT"]) self.assertEquals("http://www.someserver.com", environ["HTTP_REFERER"]) """ Test a complete request, with all typed of headers. """ def test_eviron_complete_request(self): request = { "METHOD": "GET", "VERSION": "HTTP/1.1", "PATTERN": "/py", "URI": "/py/some/path", "PATH": "/py/some/path", "QUERY": "a=1&b=4&d=4", "host": "localhost", "Accept": "*/*", "CUSTOM_HEADER": "value", "User-Agent": "some user agent/1.0", "content-length": "42", "content-type": "text/plain", "x-forwarded-for": "127.0.0.1", } environ = self.wsgid._create_wsgi_environ(request) self.assertEquals(24, len(environ)) self.assertEquals("GET", environ["REQUEST_METHOD"]) self.assertEquals("HTTP/1.1", environ["SERVER_PROTOCOL"]) self.assertEquals("/py", environ["SCRIPT_NAME"]) self.assertEquals("a=1&b=4&d=4", environ["QUERY_STRING"]) self.assertEquals("/some/path", environ["PATH_INFO"]) self.assertEquals("localhost", environ["SERVER_NAME"]) self.assertEquals("80", environ["SERVER_PORT"]) self.assertEquals("value", environ["HTTP_CUSTOM_HEADER"]) self.assertEquals("*/*", environ["HTTP_ACCEPT"]) self.assertEquals("some user agent/1.0", environ["HTTP_USER_AGENT"]) self.assertEquals("42", environ["CONTENT_LENGTH"]) self.assertEquals("42", environ["content-length"]) self.assertEquals("text/plain", environ["CONTENT_TYPE"]) self.assertEquals("text/plain", environ["content-type"]) self.assertEquals("localhost", environ["HTTP_HOST"]) self.assertEquals("127.0.0.1", environ["REMOTE_ADDR"]) """ Some values are fixed: * wsgi.multithread = False * wsgi.multiprocess = True * wsgi.run_once = True * wsgi.version = (1,0) """ def test_environ_fixed_values(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals(False, environ["wsgi.multithread"]) self.assertEquals(True, environ["wsgi.multiprocess"]) self.assertEquals(True, environ["wsgi.run_once"]) self.assertEquals((1, 0), environ["wsgi.version"]) self.assertEquals("http", environ["wsgi.url_scheme"]) self.assertEquals(sys.stderr, environ["wsgi.errors"]) def test_join_m2_chroot_to_async_upload_path(self): # The value in x-mongrel2-upload-{start,done} should be prepended with the # value of --m2-chroot, passed on the command line with patch("zmq.Context"): def _serve_request(wsgid, m2message, expected_final_path): with patch.object(wsgid, "_create_wsgi_environ"): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open") as mock_open: with patch("os.unlink"): wsgid._call_wsgi_app(message, Mock()) self.assertEquals(1, mock_open.call_count) mock_open.assert_called_with(expected_final_path) self._reparse_options("--mongrel2-chroot=/var/mongrel2") wsgid = Wsgid(app=Mock(return_value=["body response"])) message = self._create_fake_m2message("/uploads/m2.84Yet4") _serve_request(wsgid, message, "/var/mongrel2/uploads/m2.84Yet4") self._reparse_options() _serve_request(wsgid, message, "/uploads/m2.84Yet4") def test_remove_async_file_after_request_finishes_ok(self): # Since mongrel2 does not remove the originial temp file, wsgid # must remove it after the request was successfully (or not) handled. with patch("zmq.Context"): with patch("os.unlink") as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, "_create_wsgi_environ"): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app=Mock(return_value=["body response"])) message = self._create_fake_m2message("/uploads/m2.84Yet4") _serve_request(wsgid, message) mock_unlink.assert_called_with("/uploads/m2.84Yet4") def test_remove_async_file_after_failed_request(self): # Even if the request failed, wsgid must remove the temporary file. with patch("zmq.Context"): with patch("os.unlink") as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, "_create_wsgi_environ"): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app=Mock(side_effect=Exception("Failed"))) wsgid.log = Mock() message = self._create_fake_m2message("/uploads/m2.84Yet4") _serve_request(wsgid, message) mock_unlink.assert_called_with("/uploads/m2.84Yet4") def test_protect_against_exception_on_file_removal(self): with patch("zmq.Context"): with patch("os.unlink") as mock_unlink: mock_unlink.side_effect = OSError("File does not exist") def _serve_request(wsgid, m2message): with patch.object(wsgid, "_create_wsgi_environ"): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app=Mock(return_value=["body response"])) wsgid.log = Mock() message = self._create_fake_m2message("/uploads/m2.84Yet4") _serve_request(wsgid, message) self.assertEquals(1, wsgid.log.exception.call_count) def test_do_not_try_to_remove_if_not_upload_request(self): with patch("zmq.Context"): with patch("os.unlink") as mock_unlink: def _serve_request(wsgid, m2message): with patch.object(wsgid, "_create_wsgi_environ"): wsgid._create_wsgi_environ.return_value = {} with patch("__builtin__.open"): wsgid._call_wsgi_app(message, Mock()) wsgid = Wsgid(app=Mock(return_value=["body response"])) wsgid.log = Mock() message = Mock() message.headers = [] # It's not an upload message message.client_id = "uuid" message.server_id = "1" message.is_upload_done.return_value = False _serve_request(wsgid, message) self.assertEquals(0, mock_unlink.call_count) def _reparse_options(self, *args): sys.argv[1:] = args conf.settings = None parse_options() def _create_fake_m2message(self, async_upload_path): message = Mock() message.headers = {"x-mongrel2-upload-start": async_upload_path, "x-mongrel2-upload-done": async_upload_path} message.async_upload_path = async_upload_path message.server_id = "uuid" message.client_id = "42" return message
class WsgidTest(unittest.TestCase): def setUp(self): self.wsgid = Wsgid() self.sample_headers = { 'METHOD': 'GET', 'VERSION': 'HTTP/1.1', 'PATTERN': '/root', 'URI': '/more/path/', 'PATH': '/more/path', 'QUERY': 'a=1&b=4&d=4', 'host': 'localhost', 'content-length': '42', 'content-type': 'text/plain' } def tearDown(self): self.sample_headers = {} ''' Creates the SCRIPT_NAME header from the mongrel2 PATTERN header. SCRIPT_NAME should be the PATTERN without any regex parts. ''' def test_script_name_header_simple_path(self): self.sample_headers['PATTERN'] = "/py" environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/py", environ['SCRIPT_NAME']) def test_environ_script_name_header_more_comples_header(self): self.sample_headers['PATTERN'] = '/some/more/path/' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/more/path", environ['SCRIPT_NAME']) def test_environ_script_name_header_root(self): self.sample_headers['PATTERN'] = '/' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['SCRIPT_NAME']) ''' PATH_INFO comes from (URI - SCRIPT_NAME) or (PATH - SCRIPT_NAME) ''' def test_environ_path_info(self): self.sample_headers['PATTERN'] = '/py' self.sample_headers['PATH'] = '/py/some/py/path' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("/some/py/path", environ['PATH_INFO']) def test_environ_path_info_app_root(self): self.sample_headers['PATTERN'] = '/py' self.sample_headers['PATH'] = '/py' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['PATH_INFO']) def test_environ_unquoted_path_info(self): self.sample_headers['PATTERN'] = '/py/' self.sample_headers['PATH'] = '/py/so%20me/special%3f/user%40path' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('/so me/special?/user@path', environ['PATH_INFO']) ''' Generates de REQUEST_METHOD variable ''' def test_environ_request_method(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key('REQUEST_METHOD')) self.assertEquals('GET', environ['REQUEST_METHOD']) def test_environ_query_string(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("a=1&b=4&d=4", environ['QUERY_STRING']) def test_environ_no_query_string(self): #Not always we have a QUERY_STRING del self.sample_headers['QUERY'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals("", environ['QUERY_STRING']) def test_environ_server_port(self): self.sample_headers['host'] = 'localhost:443' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('443', environ['SERVER_PORT']) def test_environ_server_port_default_port(self): self.sample_headers['host'] = 'localhost' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('80', environ['SERVER_PORT']) def test_environ_server_name(self): self.sample_headers['host'] = 'localhost:8080' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost', environ['SERVER_NAME']) def test_environ_server_name_default_port(self): self.sample_headers['host'] = 'someserver' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('someserver', environ['SERVER_NAME']) ''' HTTP_HOST must inclue the port, if present. ''' def test_environ_http_host(self): self.sample_headers['host'] = 'localhost:8080' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost:8080', environ['HTTP_HOST']) def test_environ_content_type(self): self.sample_headers['content-type'] = 'application/xml' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('application/xml', environ['CONTENT_TYPE']) def test_environ_no_content_type(self): del self.sample_headers['content-type'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('', environ['CONTENT_TYPE']) def test_environ_content_length(self): self.sample_headers['content-length'] = '42' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('42', environ['CONTENT_LENGTH']) def test_environ_no_content_length(self): del self.sample_headers['content-length'] environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('', environ['CONTENT_LENGTH']) ''' Comes from mongrel2 VERSION header ''' def test_environ_server_protocol(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertTrue(environ.has_key('SERVER_PROTOCOL')) self.assertEquals('HTTP/1.1', environ['SERVER_PROTOCOL']) ''' Non Standard headers (X-) are passed untouched ''' def test_environ_non_standart_headers(self): self.sample_headers['X-Some-Header'] = 'some-value' self.sample_headers['x-other-header'] = 'other-value' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('some-value', environ['X-Some-Header']) self.assertEquals('other-value', environ['x-other-header']) def test_environ_http_host_header(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('localhost', environ['HTTP_HOST']) ''' All headers (but HTTP common headers and X- headers) must be HTTP_ suffixed ''' def test_environ_other_headers(self): self.sample_headers['my_header'] = 'some-value' self.sample_headers['OTHER_HEADER'] = 'other-value' self.sample_headers['X-Some-Header'] = 'x-header' self.sample_headers['Accept'] = '*/*' self.sample_headers['Referer'] = 'http://www.someserver.com' environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals('some-value', environ['HTTP_my_header']) self.assertEquals('other-value', environ['HTTP_OTHER_HEADER']) self.assertEquals('x-header', environ['X-Some-Header']) self.assertEquals('*/*', environ['HTTP_Accept']) self.assertEquals('http://www.someserver.com', environ['HTTP_Referer']) ''' Test a complete request, with all typed of headers. ''' def test_eviron_complete_request(self): request = { 'METHOD': 'GET', 'VERSION': 'HTTP/1.1', 'PATTERN': '/py', 'URI': '/py/some/path', 'PATH': '/py/some/path', 'QUERY': 'a=1&b=4&d=4', 'host': 'localhost', 'Accept': '*/*', 'CUSTOM_HEADER': 'value', 'User-Agent': 'some user agent/1.0', 'content-length': '42', 'content-type': 'text/plain' } environ = self.wsgid._create_wsgi_environ(request) self.assertEquals(21, len(environ)) self.assertEquals('GET', environ['REQUEST_METHOD']) self.assertEquals('HTTP/1.1', environ['SERVER_PROTOCOL']) self.assertEquals('/py', environ['SCRIPT_NAME']) self.assertEquals('a=1&b=4&d=4', environ['QUERY_STRING']) self.assertEquals('/some/path', environ['PATH_INFO']) self.assertEquals('localhost', environ['SERVER_NAME']) self.assertEquals('80', environ['SERVER_PORT']) self.assertEquals('value', environ['HTTP_CUSTOM_HEADER']) self.assertEquals('*/*', environ['HTTP_Accept']) self.assertEquals('some user agent/1.0', environ['HTTP_User-Agent']) self.assertEquals('42', environ['CONTENT_LENGTH']) self.assertEquals('42', environ['content-length']) self.assertEquals('text/plain', environ['CONTENT_TYPE']) self.assertEquals('text/plain', environ['content-type']) self.assertEquals('localhost', environ['HTTP_HOST']) ''' Some values are fixed: * wsgi.multithread = False * wsgi.multiprocess = True * wsgi.run_once = True * wsgi.version = (1,0) ''' def test_environ_fixed_values(self): environ = self.wsgid._create_wsgi_environ(self.sample_headers) self.assertEquals(False, environ['wsgi.multithread']) self.assertEquals(True, environ['wsgi.multiprocess']) self.assertEquals(True, environ['wsgi.run_once']) self.assertEquals((1,0), environ['wsgi.version']) self.assertEquals("http", environ['wsgi.url_scheme'])