Cookies not supported for other than localhost domain
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 346
- Forks
- 113
- PR merge metrics
- No merged PRs in 30d
Description
WebTest claims to support tests of WSGI as well as non WSGI applications, see Testing a non wsgi application.
However, when trying to test non-WSGI app from external domain (localhosts works well), it does not work well with cookies, which are not resent to the server with subsequent requests.
The problem can be resolved if extra_environ["HTTP_HOST"] is set properly to name of target host.
The tests were run on httpbin running on http://httpbin.org`, https://httpbin.org and on local instance on http://localhost:5000.
Local instance of httpbin was run by:
$ pip install httpbin
$ export FLASK_APP=httpbin
$ flask run
* Serving Flask app "httpbin"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Using pytest I have created simple test suite:
import pytest
from webtest import TestApp
import httpbin
apps = [("wsgiapp", httpbin.app),
("http", "http://httpbin.org"),
("https", "https://httpbin.org"),
("http#requests", "http://httpbin.org#requests"),
("https#requests", "https://httpbin.org#requests"),
("http#urllib3", "http://httpbin.org#urllib3"),
("http#restkit", "http://httpbin.org#restkit"),
("localhost_http", "http://localhost:5000"),
("localhost_http#requests", "http://localhost:5000#requests"),
("localhost_http#urllib3", "http://localhost:5000#urllib3"),
("localhost_http#restkit", "http://localhost:5000#restkit"),
]
@pytest.fixture(params=apps, ids=lambda arg: arg[0])
def testapp(request):
testid, app = request.param
testapp = TestApp(app)
return testapp
def amend_testapp(testapp):
"""Amend TestApp instance to deal with cookies properly.
`testapp` is instance of webtest.TestApp.
"""
if hasattr(testapp.app, "uri"):
from urlparse import urlparse
uri = testapp.app.uri
testapp.extra_environ["HTTP_HOST"] = urlparse(uri).hostname
return testapp
@pytest.mark.parametrize("amend", ["original", "amended"])
def test_bin(testapp, amend):
if amend == "amended":
testapp = amend_testapp(testapp)
assert not testapp.cookies, "Cookies in the testapp shall be empty initially"
# list existing cookies
res = testapp.get("/cookies")
assert not res.json["cookies"], "no cookies reported in response"
# set some cookie
cname, cval = "james", "cook"
res = testapp.get("/cookies/set", {cname: cval})
# set-cookie header shall be present in the response
print res.headers.keys()
print res.headers["set-cookie"]
print "Set-Cookie" in res.headers, "Header Set-Cookie expected in response headers"
# make sure, it is set in test testapp cookiejar
assert testapp.cookies
assert cname in testapp.cookies
assert testapp.cookies[cname] == cval
# make sure, testapp reports the cookies as being set
res = testapp.get("/cookies")
cookies = res.json["cookies"]
assert cname in cookies
assert cookies[cname] == cval
To run it, install required dependencies:
$ pip install webtest pytest wsgiproxy2 httpbin requests restkit urllib3
and run the test:
$ py.test -v tests/test_it.py
...
tests/test_it.py::test_bin[wsgiapp-original] PASSED
tests/test_it.py::test_bin[wsgiapp-amended] PASSED
tests/test_it.py::test_bin[http-original] FAILED
tests/test_it.py::test_bin[http-amended] PASSED
tests/test_it.py::test_bin[https-original] FAILED
tests/test_it.py::test_bin[https-amended] PASSED
tests/test_it.py::test_bin[http#requests-original] FAILED
tests/test_it.py::test_bin[http#requests-amended] PASSED
tests/test_it.py::test_bin[https#requests-original] FAILED
tests/test_it.py::test_bin[https#requests-amended] PASSED
tests/test_it.py::test_bin[http#urllib3-original] FAILED
tests/test_it.py::test_bin[http#urllib3-amended] PASSED
tests/test_it.py::test_bin[http#restkit-original] FAILED
tests/test_it.py::test_bin[http#restkit-amended] PASSED
tests/test_it.py::test_bin[localhost_http-original] PASSED
tests/test_it.py::test_bin[localhost_http-amended] PASSED
tests/test_it.py::test_bin[localhost_http#requests-original] PASSED
tests/test_it.py::test_bin[localhost_http#requests-amended] PASSED
tests/test_it.py::test_bin[localhost_http#urllib3-original] PASSED
tests/test_it.py::test_bin[localhost_http#urllib3-amended] PASSED
tests/test_it.py::test_bin[localhost_http#restkit-original] PASSED
tests/test_it.py::test_bin[localhost_http#restkit-amended] PASSED
Typical failure looks like:
testapp = <webtest.app.TestApp object at 0x7f046ab84350>, amend = 'original'
@pytest.mark.parametrize("amend", ["original", "amended"])
def test_bin(testapp, amend):
if amend == "amended":
testapp = amend_testapp(testapp)
assert not testapp.cookies, "Cookies in the testapp shall be empty initially"
# list existing cookies
res = testapp.get("/cookies")
assert not res.json["cookies"], "no cookies reported in response"
# set some cookie
cname, cval = "james", "cook"
res = testapp.get("/cookies/set", {cname: cval})
# set-cookie header shall be present in the response
print res.headers.keys()
print res.headers["set-cookie"]
print "Set-Cookie" in res.headers, "Header Set-Cookie expected in response headers"
# make sure, it is set in test testapp cookiejar
assert testapp.cookies
assert cname in testapp.cookies
assert testapp.cookies[cname] == cval
# make sure, testapp reports the cookies as being set
res = testapp.get("/cookies")
cookies = res.json["cookies"]
> assert cname in cookies
E assert 'james' in {}
Workaround and how it works
Whole workaround is provided in following function amend_testapp:
def amend_testapp(testapp):
"""Amend TestApp instance to deal with cookies properly.
`testapp` is instance of webtest.TestApp.
"""
if hasattr(testapp.app, "uri"):
from urlparse import urlparse
uri = testapp.app.uri
testapp.extra_environ["HTTP_HOST"] = urlparse(uri).hostname
return testapp
It gets an instance of TestApp and tries to detect, if it was created using url and not wsgi application. If the attribute "uri" of testapp.app" is present, it is likely to be based on url and not WSGI app. From theurivalue is detected hostname and set astestapp.extra_environ["HTTP_HOST"]`.
This solution shall work well in following circumstances:
- application was created either as WSGI one or by providing url (which is allowed to contain the
#{clientlibname}part like#requestsat the end. - using environmental variable
WEBTEST_TARGET_URLshall work well as we fix the testapp after it is created. - if (during creation of
testappwas anyextra_environset, it is preserved (with only exception beingHTTP_HOST).
How to fix it in WebTest library
Being able to test WSGI app as well as external ones is great feature and I think, WebTest shall keep this functional.
The question is, where shall be this fix put and options are:
WebTestlibrary itself.WsgiProxy2library, which is used to handle applications accessible via url (it provides WSGI application by proxying requests to real url).- some CookieJar implementation.
I think, that it cannot be fixed on WsgiProxy2 and CookieJar level as it is too late to fix anything.
The only place to fix is probably the WebTest library itself.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with WebTest's TestApp handling of URL-backed applications and extra_environ, then run the provided tests/test_it.py reproduction against the listed httpbin targets. Done means cookies are resent on subsequent requests to external HTTP and HTTPS domains without the amend_testapp workaround, while WSGI and localhost cases continue to pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100