from http import cookiejar as http_cookiejar from webob import Request from webob import Response from webtest.compat import to_bytes from collections import OrderedDict from webtest.debugapp import debug_app from webtest import http from tests.compat import unittest import os from unittest import mock import webtest class TestApp(unittest.TestCase): def setUp(self): self.app = webtest.TestApp(debug_app) def test_pytest_collection_disabled(self): self.assertFalse(webtest.TestApp.__test__) def test_encode_multipart_relative_to(self): app = webtest.TestApp(debug_app, relative_to=os.path.dirname(__file__)) data = app.encode_multipart( [], [('file', 'html%s404.html' % os.sep)]) self.assertIn(to_bytes('404.html'), data[-1]) def test_encode_multipart(self): data = self.app.encode_multipart( [], [('file', 'data.txt', b'data')]) self.assertIn(to_bytes('data.txt'), data[-1]) data = self.app.encode_multipart( [], [(b'file', b'data.txt', b'data')]) self.assertIn(to_bytes('data.txt'), data[-1]) data = self.app.encode_multipart( [('key', 'value')], []) self.assertIn(to_bytes('name="key"'), data[-1]) data = self.app.encode_multipart( [(b'key', b'value')], []) self.assertIn(to_bytes('name="key"'), data[-1]) def test_encode_multipart_content_type(self): data = self.app.encode_multipart( [], [('file', 'data.txt', b'data', 'text/x-custom-mime-type')]) self.assertIn(to_bytes('Content-Type: text/x-custom-mime-type'), data[-1]) data = self.app.encode_multipart( [('file', webtest.Upload('data.txt', b'data', 'text/x-custom-mime-type'))], []) self.assertIn(to_bytes('Content-Type: text/x-custom-mime-type'), data[-1]) def test_get_params(self): resp = self.app.get('/', 'a=b') resp.mustcontain('a=b') resp = self.app.get('/?a=b', dict(c='d')) resp.mustcontain('a=b', 'c=d') resp = self.app.get('/?a=b&c=d', dict(e='f')) resp.mustcontain('a=b', 'c=d', 'e=f') def test_request_with_testrequest(self): req = webtest.TestRequest.blank('/') resp = self.app.request(req, method='POST') resp.charset = 'ascii' assert 'REQUEST_METHOD: POST' in resp.text def test_patch(self): resp = self.app.patch('/') self.assertIn('PATCH', resp) resp = self.app.patch('/', xhr=True) self.assertIn('PATCH', resp) def test_custom_headers(self): resp = self.app.post('/', headers={'Accept': 'text/plain'}) resp.charset = 'ascii' assert 'HTTP_ACCEPT: text/plain' in resp.text class TestStatus(unittest.TestCase): def setUp(self): self.app = webtest.TestApp(debug_app) def check_status(self, status, awaiting_status=None): resp = Response() resp.request = Request.blank('/') resp.status = status return self.app._check_status(awaiting_status, resp) def test_check_status_asterisk(self): self.assertEqual(self.check_status('200 Ok', '*'), None) def test_check_status_almost_asterisk(self): self.assertEqual(self.check_status('200 Ok', '2*'), None) def test_check_status_tuple(self): self.assertEqual(self.check_status('200 Ok', (200,)), None) self.assertRaises(webtest.AppError, self.check_status, '200 Ok', (400,)) def test_check_status_none(self): self.assertEqual(self.check_status('200 Ok', None), None) self.assertRaises(webtest.AppError, self.check_status, '400 Ok') def test_check_status_with_custom_reason(self): self.assertEqual(self.check_status('200 Ok', '200 Ok'), None) self.assertRaises(webtest.AppError, self.check_status, '200 Ok', '200 Good Response') self.assertRaises(webtest.AppError, self.check_status, '200 Ok', '400 Bad Request') class TestParserFeature(unittest.TestCase): def test_parser_features(self): app = webtest.TestApp(debug_app, parser_features='custom') self.assertEqual(app.RequestClass.ResponseClass.parser_features, 'custom') class TestAppError(unittest.TestCase): def test_app_error(self): resp = Response(to_bytes('blah')) err = webtest.AppError('message %s', resp) self.assertEqual(err.args, ('message blah',)) def test_app_error_with_bytes_message(self): resp = Response('\xe9'.encode('utf8')) resp.charset = 'utf8' err = webtest.AppError(to_bytes('message %s'), resp) self.assertEqual(err.args, ('message \xe9',)) def test_app_error_with_unicode(self): err = webtest.AppError('messag\xe9 %s', '\xe9') self.assertEqual(err.args, ('messag\xe9 \xe9',)) def test_app_error_misc(self): resp = Response('\xe9'.encode('utf8')) resp.charset = '' # dont check the output. just make sure it doesn't fail webtest.AppError(to_bytes('message %s'), resp) webtest.AppError('messag\xe9 %s', b'\xe9') class TestPasteVariables(unittest.TestCase): def call_FUT(self, **kwargs): def application(environ, start_response): resp = Response() environ['paste.testing_variables'].update(kwargs) return resp(environ, start_response) return webtest.TestApp(application) def test_paste_testing_variables_raises(self): app = self.call_FUT(body='1') req = Request.blank('/') self.assertRaises(ValueError, app.do_request, req, '*', False) def test_paste_testing_variables(self): app = self.call_FUT(check='1') req = Request.blank('/') resp = app.do_request(req, '*', False) self.assertEqual(resp.check, '1') class TestCookies(unittest.TestCase): def test_supports_providing_cookiejar(self): cookiejar = http_cookiejar.CookieJar() app = webtest.TestApp(debug_app, cookiejar=cookiejar) self.assertIs(cookiejar, app.cookiejar) def test_set_cookie(self): def cookie_app(environ, start_response): req = Request(environ) self.assertEqual(req.cookies['foo'], 'bar') self.assertEqual(req.cookies['fizz'], ';bar=baz') status = to_bytes("200 OK") body = '' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ] start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) app.set_cookie('foo', 'bar') app.set_cookie('fizz', ';bar=baz') # Make sure we're escaping. app.get('/') app.reset() app = webtest.TestApp(cookie_app, extra_environ={'HTTP_HOST': 'testserver'}) app.set_cookie('foo', 'bar') app.set_cookie('fizz', ';bar=baz') # Make sure we're escaping. app.get('/') app.reset() def test_preserves_cookies(self): def cookie_app(environ, start_response): req = Request(environ) status = "200 OK" body = 'go' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ] if req.path_info != '/go/': headers.extend([ ('Set-Cookie', 'spam=eggs'), ('Set-Cookie', 'foo=bar;baz'), ]) else: self.assertEquals(dict(req.cookies), {'spam': 'eggs', 'foo': 'bar'}) self.assertIn('foo=bar', environ['HTTP_COOKIE']) self.assertIn('spam=eggs', environ['HTTP_COOKIE']) start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) self.assertTrue(not app.cookiejar, 'App should initially contain no cookies') self.assertFalse(app.cookies) res = app.get('/') self.assertEqual(app.cookies['spam'], 'eggs') self.assertEqual(app.cookies['foo'], 'bar') res = res.click('go') self.assertEqual(app.cookies['spam'], 'eggs') self.assertEqual(app.cookies['foo'], 'bar') app.reset() self.assertFalse(bool(app.cookies)) def test_secure_cookies(self): def cookie_app(environ, start_response): req = Request(environ) status = "200 OK" body = 'go' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ] if req.path_info != '/go/': headers.extend([ ('Set-Cookie', 'spam=eggs; secure'), ('Set-Cookie', 'foo=bar;baz; secure'), ]) else: self.assertEquals(dict(req.cookies), {'spam': 'eggs', 'foo': 'bar'}) self.assertIn('foo=bar', environ['HTTP_COOKIE']) self.assertIn('spam=eggs', environ['HTTP_COOKIE']) start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) self.assertFalse(app.cookies) res = app.get('https://localhost/') self.assertEqual(app.cookies['spam'], 'eggs') self.assertEqual(app.cookies['foo'], 'bar') res = res.click('go') self.assertEqual(app.cookies['spam'], 'eggs') self.assertEqual(app.cookies['foo'], 'bar') def test_cookies_readonly(self): app = webtest.TestApp(debug_app) try: app.cookies = {} except: pass else: self.fail('testapp.cookies should be read-only') @mock.patch('http.cookiejar.time.time') def test_expires_cookies(self, mock_time): def cookie_app(environ, start_response): status = to_bytes("200 OK") body = '' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ('Set-Cookie', 'spam=eggs; Expires=Tue, 21-Feb-2013 17:45:00 GMT;'), ] start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) self.assertTrue(not app.cookiejar, 'App should initially contain no cookies') mock_time.return_value = 1361464946.0 app.get('/') self.assertTrue(app.cookies, 'Response should have set cookies') mock_time.return_value = 1461464946.0 app.get('/') self.assertFalse(app.cookies, 'Response should have unset cookies') def test_http_cookie(self): def cookie_app(environ, start_response): req = Request(environ) status = to_bytes("200 OK") body = 'Cookie.' assert dict(req.cookies) == {'spam': 'eggs'} assert environ['HTTP_COOKIE'] == 'spam=eggs' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ] start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) self.assertTrue(not app.cookies, 'App should initially contain no cookies') res = app.get('/', headers=[('Cookie', 'spam=eggs')]) self.assertFalse(app.cookies, 'Response should not have set cookies') self.assertEqual(res.request.environ['HTTP_COOKIE'], 'spam=eggs') self.assertEqual(dict(res.request.cookies), {'spam': 'eggs'}) def test_http_localhost_cookie(self): def cookie_app(environ, start_response): status = to_bytes("200 OK") body = 'Cookie.' headers = [ ('Content-Type', 'text/html'), ('Content-Length', str(len(body))), ('Set-Cookie', 'spam=eggs; Domain=localhost;'), ] start_response(status, headers) return [to_bytes(body)] app = webtest.TestApp(cookie_app) self.assertTrue(not app.cookies, 'App should initially contain no cookies') res = app.get('/') res = app.get('/') self.assertTrue(app.cookies, 'Response should not have set cookies') self.assertEqual(res.request.environ['HTTP_COOKIE'], 'spam=eggs') self.assertEqual(dict(res.request.cookies), {'spam': 'eggs'}) def test_cookie_policy(self): def cookie_app(environ, start_response): status = to_bytes("200 OK") body = 'Cookie.' headers = [ ('Content-Type', 'text/plain'), ('Content-Length', str(len(body))), ('Set-Cookie', 'spam=eggs; secure; Domain=.example.org;'), ] start_response(status, headers) return [to_bytes(body)] policy = webtest.app.CookiePolicy() flags = ( policy.DomainStrictNoDots | policy.DomainRFC2965Match | policy.DomainStrictNonDomain) policy.strict_ns_domain |= flags cookiejar = http_cookiejar.CookieJar(policy=policy) app = webtest.TestApp( cookie_app, cookiejar=cookiejar, extra_environ={'HTTP_HOST': 'example.org'}) res = app.get('/') res = app.get('/') self.assertFalse(app.cookies, 'Response should not have set cookies') self.assertNotIn('HTTP_COOKIE', res.request.environ) self.assertEqual(dict(res.request.cookies), {}) class TestEnviron(unittest.TestCase): def test_get_extra_environ(self): app = webtest.TestApp(debug_app, extra_environ={'HTTP_ACCEPT_LANGUAGE': 'ru', 'foo': 'bar'}) res = app.get('http://localhost/') self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'bar'", res, res) res = app.get('http://localhost/', extra_environ={'foo': 'baz'}) self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'baz'", res, res) def test_post_extra_environ(self): app = webtest.TestApp(debug_app, extra_environ={'HTTP_ACCEPT_LANGUAGE': 'ru', 'foo': 'bar'}) res = app.post('http://localhost/') self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'bar'", res, res) res = app.post('http://localhost/', extra_environ={'foo': 'baz'}) self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'baz'", res, res) def test_request_extra_environ(self): app = webtest.TestApp(debug_app, extra_environ={'HTTP_ACCEPT_LANGUAGE': 'ru', 'foo': 'bar'}) res = app.request('http://localhost/', method='GET') self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'bar'", res, res) res = app.request('http://localhost/', method='GET', environ={'foo': 'baz'}) self.assertIn('HTTP_ACCEPT_LANGUAGE: ru', res, res) self.assertIn("foo: 'baz'", res, res) deform_upload_fields_text = """ """ def get_submit_app(form_id, form_fields_text): def submit_app(environ, start_response): req = Request(environ) status = "200 OK" if req.method == "GET": body = """ form page
%s
""" % (form_id, form_fields_text) else: body_head = """ display page """ body_parts = [] for (name, value) in req.POST.items(): if hasattr(value, 'filename'): body_parts.append("%s:%s:%s\n" % ( name, value.filename, value.value.decode('ascii'))) else: body_parts.append("%s:%s\n" % ( name, value)) body_foot = """ """ body = body_head + "".join(body_parts) + body_foot if not isinstance(body, bytes): body = body.encode('utf8') headers = [ ('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', str(len(body)))] start_response(status, headers) return [body] return submit_app class TestFieldOrder(unittest.TestCase): def test_submit_with_file_upload(self): uploaded_file_name = 'test.txt' uploaded_file_contents = to_bytes('test content file upload') deform_upload_file_app = get_submit_app('deform', deform_upload_fields_text) app = webtest.TestApp(deform_upload_file_app) res = app.get('/') self.assertEqual(res.status_int, 200) self.assertEqual( res.headers['content-type'], 'text/html; charset=utf-8') self.assertEqual(res.content_type, 'text/html') self.assertEqual(res.charset, 'utf-8') single_form = res.forms["deform"] single_form.set("title", "testtitle") single_form.set("fileupload", (uploaded_file_name, uploaded_file_contents)) single_form.set("description", "testdescription") display = single_form.submit("Submit") self.assertIn(""" _charset_: __formid__:deform title:testtitle __start__:fileupload:mapping fileupload:test.txt:test content file upload __end__:fileupload:mapping description:testdescription Submit:Submit """.strip(), display, display) def test_post_with_file_upload(self): uploaded_file_name = 'test.txt' uploaded_file_contents = to_bytes('test content file upload') deform_upload_file_app = get_submit_app('deform', deform_upload_fields_text) app = webtest.TestApp(deform_upload_file_app) display = app.post("/", OrderedDict([ ('_charset_', ''), ('__formid__', 'deform'), ('title', 'testtitle'), ('__start__', 'fileupload:mapping'), ('fileupload', webtest.Upload(uploaded_file_name, uploaded_file_contents)), ('__end__', 'fileupload:mapping'), ('description', 'testdescription'), ('Submit', 'Submit')])) self.assertIn(""" _charset_: __formid__:deform title:testtitle __start__:fileupload:mapping fileupload:test.txt:test content file upload __end__:fileupload:mapping description:testdescription Submit:Submit""".strip(), display, display) def test_field_order_is_across_all_fields(self): fields = """ """ submit_app = get_submit_app('test', fields) app = webtest.TestApp(submit_app) get_res = app.get("/") # Submit the form with the second submit button. display = get_res.forms[0].submit('save', 1) self.assertIn(""" letter:a letter:b number:1 letter:c number:2 letter:d save:Save 2 letter:e""".strip(), display, display) class TestFragments(unittest.TestCase): def test_url_without_fragments(self): app = webtest.TestApp(debug_app) res = app.get('http://localhost/') self.assertEqual(res.status_int, 200) def test_url_with_fragments(self): app = webtest.TestApp(debug_app) res = app.get('http://localhost/#ananchor') self.assertEqual(res.status_int, 200) def application(environ, start_response): req = Request(environ) if req.path_info == '/redirect': req.path_info = '/path' resp = Response() resp.status = '302 Found' resp.location = req.path else: resp = Response() resp.body = to_bytes( 'link' % req.path) return resp(environ, start_response) class TestScriptName(unittest.TestCase): def test_script_name(self): app = webtest.TestApp(application) resp = app.get('/script', extra_environ={'SCRIPT_NAME': '/script'}) resp.mustcontain('href="/script"') resp = app.get('/script/redirect', extra_environ={'SCRIPT_NAME': '/script'}) self.assertEqual(resp.status_int, 302) self.assertEqual(resp.location, 'http://localhost/script/path', resp.location) resp = resp.follow(extra_environ={'SCRIPT_NAME': '/script'}) resp.mustcontain('href="/script/path"') resp = resp.click('link') resp.mustcontain('href="/script/path"') def test_app_script_name(self): app = webtest.TestApp(application, extra_environ={'SCRIPT_NAME': '/script'}) resp = app.get('/script/redirect') self.assertEqual(resp.status_int, 302) self.assertEqual(resp.location, 'http://localhost/script/path', resp.location) resp = resp.follow() resp.mustcontain('href="/script/path"') resp = resp.click('link') resp.mustcontain('href="/script/path"') def test_script_name_doesnt_match(self): app = webtest.TestApp(application) resp = app.get('/path', extra_environ={'SCRIPT_NAME': '/script'}) resp.mustcontain('href="/script/path"') class TestWSGIProxy(unittest.TestCase): def setUp(self): self.s = http.StopableWSGIServer.create(debug_app) self.s.wait() def test_proxy_with_url(self): app = webtest.TestApp(self.s.application_url) resp = app.get('/') self.assertEqual(resp.status_int, 200) def test_proxy_with_environ(self): def app(environ, start_response): pass os.environ['WEBTEST_TARGET_URL'] = self.s.application_url app = webtest.TestApp(app) del os.environ['WEBTEST_TARGET_URL'] resp = app.get('/') self.assertEqual(resp.status_int, 200) def tearDown(self): self.s.shutdown() class TestAppXhrParam(unittest.TestCase): def setUp(self): self.app = webtest.TestApp(debug_app) def test_xhr_param_change_headers(self): app = self.app # FIXME: this test isn`t work for head request # now I don't know how to test head request functions = (app.get, app.post, app.delete, app.put, app.options) # app.head for func in functions: resp = func('/', xhr=True) resp.charset = 'ascii' self.assertIn('HTTP_X_REQUESTED_WITH: XMLHttpRequest', resp.text)