forked from github.com/pypiserver
fmt: tests/test_app.py
This commit is contained in:
parent
9496be122f
commit
a52c0d6f4c
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
# Builtin imports
|
# Builtin imports
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
try: # python 3
|
try: # python 3
|
||||||
@ -9,6 +10,7 @@ try: # python 3
|
|||||||
from html import unescape
|
from html import unescape
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from HTMLParser import HTMLParser
|
from HTMLParser import HTMLParser
|
||||||
|
|
||||||
unescape = HTMLParser().unescape
|
unescape = HTMLParser().unescape
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -40,6 +42,7 @@ def _app(app):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def app(tmpdir):
|
def app(tmpdir):
|
||||||
from pypiserver import app
|
from pypiserver import app
|
||||||
|
|
||||||
return app(root=tmpdir.strpath, authenticated=[])
|
return app(root=tmpdir.strpath, authenticated=[])
|
||||||
|
|
||||||
|
|
||||||
@ -70,15 +73,17 @@ def testpriv(priv):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def search_xml():
|
def search_xml():
|
||||||
"""Return an xml dom suitable for passing to search"""
|
"""Return an xml dom suitable for passing to search"""
|
||||||
xml = '<xml><methodName>search</methodName><string>test</string></xml>'
|
xml = "<xml><methodName>search</methodName><string>test</string></xml>"
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=[
|
@pytest.fixture(
|
||||||
" ", # Mustcontain test below fails when string is empty.
|
params=[
|
||||||
"Hey there!",
|
" ", # Mustcontain test below fails when string is empty.
|
||||||
"<html><body>Hey there!</body></html>",
|
"Hey there!",
|
||||||
])
|
"<html><body>Hey there!</body></html>",
|
||||||
|
]
|
||||||
|
)
|
||||||
def welcome_file_no_vars(request, root):
|
def welcome_file_no_vars(request, root):
|
||||||
"""Welcome file fixture
|
"""Welcome file fixture
|
||||||
|
|
||||||
@ -127,37 +132,45 @@ def test_root_hostname(testapp):
|
|||||||
|
|
||||||
def test_root_welcome_msg_no_vars(root, welcome_file_no_vars):
|
def test_root_welcome_msg_no_vars(root, welcome_file_no_vars):
|
||||||
from pypiserver import app
|
from pypiserver import app
|
||||||
|
|
||||||
app = app(root=root.strpath, welcome_file=welcome_file_no_vars.strpath)
|
app = app(root=root.strpath, welcome_file=welcome_file_no_vars.strpath)
|
||||||
testapp = webtest.TestApp(app)
|
testapp = webtest.TestApp(app)
|
||||||
resp = testapp.get("/")
|
resp = testapp.get("/")
|
||||||
from pypiserver import __version__ as pver
|
from pypiserver import __version__ as pver
|
||||||
|
|
||||||
resp.mustcontain(welcome_file_no_vars.read(), no=pver)
|
resp.mustcontain(welcome_file_no_vars.read(), no=pver)
|
||||||
|
|
||||||
|
|
||||||
def test_root_welcome_msg_all_vars(root, welcome_file_all_vars):
|
def test_root_welcome_msg_all_vars(root, welcome_file_all_vars):
|
||||||
from pypiserver import app
|
from pypiserver import app
|
||||||
|
|
||||||
app = app(root=root.strpath, welcome_file=welcome_file_all_vars.strpath)
|
app = app(root=root.strpath, welcome_file=welcome_file_all_vars.strpath)
|
||||||
testapp = webtest.TestApp(app)
|
testapp = webtest.TestApp(app)
|
||||||
resp = testapp.get("/")
|
resp = testapp.get("/")
|
||||||
|
|
||||||
from pypiserver import __version__ as pver
|
from pypiserver import __version__ as pver
|
||||||
|
|
||||||
resp.mustcontain(pver)
|
resp.mustcontain(pver)
|
||||||
|
|
||||||
|
|
||||||
def test_root_welcome_msg_antiXSS(testapp):
|
def test_root_welcome_msg_antiXSS(testapp):
|
||||||
"""https://github.com/pypiserver/pypiserver/issues/77"""
|
"""https://github.com/pypiserver/pypiserver/issues/77"""
|
||||||
resp = testapp.get(
|
resp = testapp.get("/?<alert>Red</alert>", headers={"Host": "somehost.org"})
|
||||||
"/?<alert>Red</alert>", headers={"Host": "somehost.org"})
|
|
||||||
resp.mustcontain("alert", "somehost.org", no="<alert>")
|
resp.mustcontain("alert", "somehost.org", no="<alert>")
|
||||||
|
|
||||||
|
|
||||||
def test_root_remove_not_found_msg_antiXSS(testapp):
|
def test_root_remove_not_found_msg_antiXSS(testapp):
|
||||||
"""https://github.com/pypiserver/pypiserver/issues/77"""
|
"""https://github.com/pypiserver/pypiserver/issues/77"""
|
||||||
resp = testapp.post("/", expect_errors=True,
|
resp = testapp.post(
|
||||||
headers={"Host": "somehost.org"},
|
"/",
|
||||||
params={':action': 'remove_pkg',
|
expect_errors=True,
|
||||||
'name': '<alert>Red</alert>',
|
headers={"Host": "somehost.org"},
|
||||||
'version': '1.1.1'})
|
params={
|
||||||
|
":action": "remove_pkg",
|
||||||
|
"name": "<alert>Red</alert>",
|
||||||
|
"version": "1.1.1",
|
||||||
|
},
|
||||||
|
)
|
||||||
resp.mustcontain("alert", "somehost.org", no="<alert>")
|
resp.mustcontain("alert", "somehost.org", no="<alert>")
|
||||||
|
|
||||||
|
|
||||||
@ -165,7 +178,7 @@ def test_packages_redirect(testapp):
|
|||||||
resp = testapp.get("/packages")
|
resp = testapp.get("/packages")
|
||||||
assert resp.status_code >= 300
|
assert resp.status_code >= 300
|
||||||
assert resp.status_code < 400
|
assert resp.status_code < 400
|
||||||
assert resp.location.endswith('/packages/')
|
assert resp.location.endswith("/packages/")
|
||||||
|
|
||||||
|
|
||||||
def test_packages_empty(testapp):
|
def test_packages_empty(testapp):
|
||||||
@ -203,7 +216,7 @@ def test_simple_redirect(testapp):
|
|||||||
resp = testapp.get("/simple")
|
resp = testapp.get("/simple")
|
||||||
assert resp.status_code >= 300
|
assert resp.status_code >= 300
|
||||||
assert resp.status_code < 400
|
assert resp.status_code < 400
|
||||||
assert resp.location.endswith('/simple/')
|
assert resp.location.endswith("/simple/")
|
||||||
|
|
||||||
|
|
||||||
def test_simple_list_no_dotfiles(root, testapp):
|
def test_simple_list_no_dotfiles(root, testapp):
|
||||||
@ -245,21 +258,24 @@ def test_simple_name_redirect(testapp):
|
|||||||
resp = testapp.get("/simple/foobar")
|
resp = testapp.get("/simple/foobar")
|
||||||
assert resp.status_code >= 300
|
assert resp.status_code >= 300
|
||||||
assert resp.status_code < 400
|
assert resp.status_code < 400
|
||||||
assert resp.location.endswith('/simple/foobar/')
|
assert resp.location.endswith("/simple/foobar/")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('package,normalized', [
|
@pytest.mark.parametrize(
|
||||||
('FooBar', 'foobar'),
|
"package,normalized",
|
||||||
('Foo.Bar', 'foo-bar'),
|
[
|
||||||
('foo_bar', 'foo-bar'),
|
("FooBar", "foobar"),
|
||||||
('Foo-Bar', 'foo-bar'),
|
("Foo.Bar", "foo-bar"),
|
||||||
('foo--_.bar', 'foo-bar'),
|
("foo_bar", "foo-bar"),
|
||||||
])
|
("Foo-Bar", "foo-bar"),
|
||||||
|
("foo--_.bar", "foo-bar"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_simple_normalized_name_redirect(testapp, package, normalized):
|
def test_simple_normalized_name_redirect(testapp, package, normalized):
|
||||||
resp = testapp.get("/simple/{0}/".format(package))
|
resp = testapp.get("/simple/{0}/".format(package))
|
||||||
assert resp.status_code >= 300
|
assert resp.status_code >= 300
|
||||||
assert resp.status_code < 400
|
assert resp.status_code < 400
|
||||||
assert resp.location.endswith('/simple/{0}/'.format(normalized))
|
assert resp.location.endswith("/simple/{0}/".format(normalized))
|
||||||
|
|
||||||
|
|
||||||
def test_simple_index(root, testapp):
|
def test_simple_index(root, testapp):
|
||||||
@ -316,7 +332,9 @@ def test_nonroot_simple_index(root, testpriv):
|
|||||||
|
|
||||||
def test_nonroot_simple_index_with_x_forwarded_host(root, testapp):
|
def test_nonroot_simple_index_with_x_forwarded_host(root, testapp):
|
||||||
root.join("foobar-1.0.zip").write("")
|
root.join("foobar-1.0.zip").write("")
|
||||||
resp = testapp.get("/simple/foobar/", headers={"X-Forwarded-Host": "forwarded.ed/priv/"})
|
resp = testapp.get(
|
||||||
|
"/simple/foobar/", headers={"X-Forwarded-Host": "forwarded.ed/priv/"}
|
||||||
|
)
|
||||||
links = resp.html("a")
|
links = resp.html("a")
|
||||||
assert len(links) == 1
|
assert len(links) == 1
|
||||||
assert links[0]["href"].startswith("/priv/packages/foobar-1.0.zip#")
|
assert links[0]["href"].startswith("/priv/packages/foobar-1.0.zip#")
|
||||||
@ -332,7 +350,9 @@ def test_nonroot_simple_packages(root, testpriv):
|
|||||||
|
|
||||||
def test_nonroot_simple_packages_with_x_forwarded_host(root, testapp):
|
def test_nonroot_simple_packages_with_x_forwarded_host(root, testapp):
|
||||||
root.join("foobar-1.0.zip").write("123")
|
root.join("foobar-1.0.zip").write("123")
|
||||||
resp = testapp.get("/packages/", headers={"X-Forwarded-Host": "forwarded/priv/"})
|
resp = testapp.get(
|
||||||
|
"/packages/", headers={"X-Forwarded-Host": "forwarded/priv/"}
|
||||||
|
)
|
||||||
links = resp.html("a")
|
links = resp.html("a")
|
||||||
assert len(links) == 1
|
assert len(links) == 1
|
||||||
assert links[0]["href"].startswith("/priv/packages/foobar-1.0.zip#")
|
assert links[0]["href"].startswith("/priv/packages/foobar-1.0.zip#")
|
||||||
@ -342,8 +362,11 @@ def test_root_no_relative_paths(testpriv):
|
|||||||
"""https://github.com/pypiserver/pypiserver/issues/25"""
|
"""https://github.com/pypiserver/pypiserver/issues/25"""
|
||||||
resp = testpriv.get("/priv/")
|
resp = testpriv.get("/priv/")
|
||||||
hrefs = [x["href"] for x in resp.html("a")]
|
hrefs = [x["href"] for x in resp.html("a")]
|
||||||
assert hrefs == ['/priv/packages/', '/priv/simple/',
|
assert hrefs == [
|
||||||
'https://pypi.org/project/pypiserver/']
|
"/priv/packages/",
|
||||||
|
"/priv/simple/",
|
||||||
|
"https://pypi.org/project/pypiserver/",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_simple_index_list_no_duplicates(root, testapp):
|
def test_simple_index_list_no_duplicates(root, testapp):
|
||||||
@ -391,103 +414,121 @@ def test_no_cache_control_set(root, _app, testapp):
|
|||||||
|
|
||||||
def test_cache_control_set(root):
|
def test_cache_control_set(root):
|
||||||
from pypiserver import app
|
from pypiserver import app
|
||||||
|
|
||||||
AGE = 86400
|
AGE = 86400
|
||||||
app_with_cache = webtest.TestApp(app(root=root.strpath, cache_control=AGE))
|
app_with_cache = webtest.TestApp(app(root=root.strpath, cache_control=AGE))
|
||||||
root.join("foo_bar-1.0.tar.gz").write("")
|
root.join("foo_bar-1.0.tar.gz").write("")
|
||||||
resp = app_with_cache.get("/packages/foo_bar-1.0.tar.gz")
|
resp = app_with_cache.get("/packages/foo_bar-1.0.tar.gz")
|
||||||
assert "Cache-Control" in resp.headers
|
assert "Cache-Control" in resp.headers
|
||||||
assert resp.headers["Cache-Control"] == 'public, max-age=%s' % AGE
|
assert resp.headers["Cache-Control"] == "public, max-age=%s" % AGE
|
||||||
|
|
||||||
|
|
||||||
def test_upload_noAction(root, testapp):
|
def test_upload_noAction(root, testapp):
|
||||||
resp = testapp.post("/", expect_errors=1)
|
resp = testapp.post("/", expect_errors=1)
|
||||||
assert resp.status == '400 Bad Request'
|
assert resp.status == "400 Bad Request"
|
||||||
assert "Missing ':action' field!" in unescape(resp.text)
|
assert "Missing ':action' field!" in unescape(resp.text)
|
||||||
|
|
||||||
|
|
||||||
def test_upload_badAction(root, testapp):
|
def test_upload_badAction(root, testapp):
|
||||||
resp = testapp.post("/", params={':action': 'BAD'}, expect_errors=1)
|
resp = testapp.post("/", params={":action": "BAD"}, expect_errors=1)
|
||||||
assert resp.status == '400 Bad Request'
|
assert resp.status == "400 Bad Request"
|
||||||
assert "Unsupported ':action' field: BAD" in unescape(resp.text)
|
assert "Unsupported ':action' field: BAD" in unescape(resp.text)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("package", [f[0]
|
@pytest.mark.parametrize(
|
||||||
for f in test_core.files
|
"package", [f[0] for f in test_core.files if f[1] and "/" not in f[0]]
|
||||||
if f[1] and '/' not in f[0]])
|
)
|
||||||
def test_upload(package, root, testapp):
|
def test_upload(package, root, testapp):
|
||||||
resp = testapp.post("/", params={':action': 'file_upload'},
|
resp = testapp.post(
|
||||||
upload_files=[('content', package, b'')])
|
"/",
|
||||||
|
params={":action": "file_upload"},
|
||||||
|
upload_files=[("content", package, b"")],
|
||||||
|
)
|
||||||
assert resp.status_int == 200
|
assert resp.status_int == 200
|
||||||
uploaded_pkgs = [f.basename for f in root.listdir()]
|
uploaded_pkgs = [f.basename for f in root.listdir()]
|
||||||
assert len(uploaded_pkgs) == 1
|
assert len(uploaded_pkgs) == 1
|
||||||
assert uploaded_pkgs[0].lower() == package.lower()
|
assert uploaded_pkgs[0].lower() == package.lower()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("package", [f[0]
|
@pytest.mark.parametrize(
|
||||||
for f in test_core.files
|
"package", [f[0] for f in test_core.files if f[1] and "/" not in f[0]]
|
||||||
if f[1] and '/' not in f[0]])
|
)
|
||||||
def test_upload_with_signature(package, root, testapp):
|
def test_upload_with_signature(package, root, testapp):
|
||||||
resp = testapp.post("/", params={':action': 'file_upload'},
|
resp = testapp.post(
|
||||||
upload_files=[
|
"/",
|
||||||
('content', package, b''),
|
params={":action": "file_upload"},
|
||||||
('gpg_signature', '%s.asc' % package, b'')])
|
upload_files=[
|
||||||
|
("content", package, b""),
|
||||||
|
("gpg_signature", "%s.asc" % package, b""),
|
||||||
|
],
|
||||||
|
)
|
||||||
assert resp.status_int == 200
|
assert resp.status_int == 200
|
||||||
uploaded_pkgs = [f.basename.lower() for f in root.listdir()]
|
uploaded_pkgs = [f.basename.lower() for f in root.listdir()]
|
||||||
assert len(uploaded_pkgs) == 2
|
assert len(uploaded_pkgs) == 2
|
||||||
assert package.lower() in uploaded_pkgs
|
assert package.lower() in uploaded_pkgs
|
||||||
assert '%s.asc' % package.lower() in uploaded_pkgs
|
assert "%s.asc" % package.lower() in uploaded_pkgs
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("package", [
|
@pytest.mark.parametrize(
|
||||||
f[0] for f in test_core.files
|
"package", [f[0] for f in test_core.files if f[1] is None]
|
||||||
if f[1] is None])
|
)
|
||||||
def test_upload_badFilename(package, root, testapp):
|
def test_upload_badFilename(package, root, testapp):
|
||||||
resp = testapp.post("/", params={':action': 'file_upload'},
|
resp = testapp.post(
|
||||||
upload_files=[('content', package, b'')],
|
"/",
|
||||||
expect_errors=1)
|
params={":action": "file_upload"},
|
||||||
assert resp.status == '400 Bad Request'
|
upload_files=[("content", package, b"")],
|
||||||
|
expect_errors=1,
|
||||||
|
)
|
||||||
|
assert resp.status == "400 Bad Request"
|
||||||
assert "Bad filename: %s" % package in resp.text
|
assert "Bad filename: %s" % package in resp.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(("name", "version"), [
|
@pytest.mark.parametrize(
|
||||||
|
("name", "version"),
|
||||||
|
[
|
||||||
(None, None),
|
(None, None),
|
||||||
(None, ''),
|
(None, ""),
|
||||||
('', None),
|
("", None),
|
||||||
(None, '1'),
|
(None, "1"),
|
||||||
('pkg', None),
|
("pkg", None),
|
||||||
('', '1'),
|
("", "1"),
|
||||||
('pkg', ''),
|
("pkg", ""),
|
||||||
])
|
],
|
||||||
|
)
|
||||||
def test_remove_pkg_missingNaveVersion(name, version, root, testapp):
|
def test_remove_pkg_missingNaveVersion(name, version, root, testapp):
|
||||||
msg = "Missing 'name'/'version' fields: name=%s, version=%s"
|
msg = "Missing 'name'/'version' fields: name=%s, version=%s"
|
||||||
params = {':action': 'remove_pkg', 'name': name, 'version': version}
|
params = {":action": "remove_pkg", "name": name, "version": version}
|
||||||
params = dict((k, v) for k, v in params.items() if v is not None)
|
params = dict((k, v) for k, v in params.items() if v is not None)
|
||||||
resp = testapp.post("/", expect_errors=1, params=params)
|
resp = testapp.post("/", expect_errors=1, params=params)
|
||||||
|
|
||||||
assert resp.status == '400 Bad Request'
|
assert resp.status == "400 Bad Request"
|
||||||
assert msg % (name, version) in unescape(resp.text)
|
assert msg % (name, version) in unescape(resp.text)
|
||||||
|
|
||||||
|
|
||||||
def test_remove_pkg_notFound(root, testapp):
|
def test_remove_pkg_notFound(root, testapp):
|
||||||
resp = testapp.post("/", expect_errors=1,
|
resp = testapp.post(
|
||||||
params={
|
"/",
|
||||||
':action': 'remove_pkg',
|
expect_errors=1,
|
||||||
'name': 'foo',
|
params={":action": "remove_pkg", "name": "foo", "version": "123"},
|
||||||
'version': '123',
|
)
|
||||||
})
|
assert resp.status == "404 Not Found"
|
||||||
assert resp.status == '404 Not Found'
|
|
||||||
assert "foo (123) not found" in unescape(resp.text)
|
assert "foo (123) not found" in unescape(resp.text)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('pkgs,matches', [
|
@pytest.mark.parametrize(
|
||||||
([], []),
|
"pkgs,matches",
|
||||||
(['test-1.0.tar.gz'], [('test', '1.0')]),
|
[
|
||||||
(['test-1.0.tar.gz', 'test-test-2.0.1.tar.gz'],
|
([], []),
|
||||||
[('test', '1.0'), ('test-test', '2.0.1')]),
|
(["test-1.0.tar.gz"], [("test", "1.0")]),
|
||||||
(['test-1.0.tar.gz', 'other-2.0.tar.gz'], [('test', '1.0')]),
|
(
|
||||||
(['test-2.0-py2.py3-none-any.whl'], [('test', '2.0')]),
|
["test-1.0.tar.gz", "test-test-2.0.1.tar.gz"],
|
||||||
(['other-2.0.tar.gz'], [])
|
[("test", "1.0"), ("test-test", "2.0.1")],
|
||||||
])
|
),
|
||||||
|
(["test-1.0.tar.gz", "other-2.0.tar.gz"], [("test", "1.0")]),
|
||||||
|
(["test-2.0-py2.py3-none-any.whl"], [("test", "2.0")]),
|
||||||
|
(["other-2.0.tar.gz"], []),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_search(root, testapp, search_xml, pkgs, matches):
|
def test_search(root, testapp, search_xml, pkgs, matches):
|
||||||
"""Test the search functionality at the RPC2 endpoint
|
"""Test the search functionality at the RPC2 endpoint
|
||||||
|
|
||||||
@ -520,18 +561,18 @@ def test_search(root, testapp, search_xml, pkgs, matches):
|
|||||||
version) matches for the "test" query
|
version) matches for the "test" query
|
||||||
"""
|
"""
|
||||||
for pkg in pkgs:
|
for pkg in pkgs:
|
||||||
root.join(pkg).write('')
|
root.join(pkg).write("")
|
||||||
resp = testapp.post('/RPC2', search_xml)
|
resp = testapp.post("/RPC2", search_xml)
|
||||||
parsed = xmlrpclib.loads(resp.text)
|
parsed = xmlrpclib.loads(resp.text)
|
||||||
assert len(parsed) == 2 and parsed[1] == 'search'
|
assert len(parsed) == 2 and parsed[1] == "search"
|
||||||
if not matches:
|
if not matches:
|
||||||
assert len(parsed[0]) == 1 and not parsed[0][0]
|
assert len(parsed[0]) == 1 and not parsed[0][0]
|
||||||
else:
|
else:
|
||||||
assert len(parsed[0][0]) == len(matches) and parsed[0][0]
|
assert len(parsed[0][0]) == len(matches) and parsed[0][0]
|
||||||
for returned in parsed[0][0]:
|
for returned in parsed[0][0]:
|
||||||
print(returned)
|
print(returned)
|
||||||
assert returned['name'] in [match[0] for match in matches]
|
assert returned["name"] in [match[0] for match in matches]
|
||||||
assert returned['version'] in [match[1] for match in matches]
|
assert returned["version"] in [match[1] for match in matches]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail()
|
@pytest.mark.xfail()
|
||||||
|
Loading…
Reference in New Issue
Block a user