blob: 4bc82986001398f9086d245a46d404f7798c8d12 [file] [log] [blame] [edit]
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 = '<html><body><a href="/go/">go</a></body></html>'
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 = '<html><body><a href="/go/">go</a></body></html>'
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 = """
<input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="deform"/>
<input type="text" name="title" value="" id="deformField1"/>
<input type="hidden" name="__start__" value="fileupload:mapping"/>
<input type="file" name="fileupload" id="deformField2"/>
<input type="hidden" name="__end__" value="fileupload:mapping"/>
<textarea id="deformField3" name="description" rows="10" cols="60">
</textarea>
<button
id="deformSubmit"
name="Submit"
type="submit"
value="Submit">
Submit
</button>
"""
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 = """
<html>
<head><title>form page</title></head>
<body>
<form
id="%s"
action=""
method="POST"
enctype="multipart/form-data"
accept-charset="utf-8">
%s
</form>
</body>
</html>
""" % (form_id, form_fields_text)
else:
body_head = """
<html>
<head><title>display page</title></head>
<body>
"""
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>
</html>
"""
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 = """
<input type="text" name="letter" value="a">
<input type="text" name="letter" value="b">
<input type="text" name="number" value="1">
<input type="text" name="letter" value="c">
<input type="text" name="number" value="2">
<input type="submit" name="save" value="Save 1">
<input type="text" name="letter" value="d">
<input type="submit" name="save" value="Save 2">
<input type="text" name="letter" value="e">
"""
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(
'<html><body><a href="%s">link</a></body></html>' % 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)