From 6169afc266f367c0ab488ea0770fa43545d19d30 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Sun, 10 Feb 2019 14:40:11 +0100 Subject: [PATCH] Initial tests --- .gitignore | 5 ++ servefile | 2 +- tests/test_servefile.py | 159 ++++++++++++++++++++++++++++++++++++++++ tox.ini | 8 ++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 tests/test_servefile.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 3400509..2d17488 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ MANIFEST dist/ +*.pyc +__pycache__ +*.swp +servefile.egg-info +.tox diff --git a/servefile b/servefile index 0734c79..5dda804 100755 --- a/servefile +++ b/servefile @@ -7,7 +7,7 @@ from __future__ import print_function -__version__ = '0.4.4' +__version__ = '0.4.5-unreleased' import argparse import base64 diff --git a/tests/test_servefile.py b/tests/test_servefile.py new file mode 100644 index 0000000..12766ac --- /dev/null +++ b/tests/test_servefile.py @@ -0,0 +1,159 @@ +import pytest +import requests +import time +import subprocess + + +@pytest.fixture +def run_servefile(): + instances = [] + + def _run_servefile(args, **kwargs): + if not isinstance(args, list): + args = [args] + print("running with args", args) + p = subprocess.Popen(['servefile'] + args, **kwargs) + time.sleep(kwargs.get('timeout', 0.1)) + instances.append(p) + + return p + + yield _run_servefile + + for instance in instances: + try: + instance.terminate() + except OSError: + pass + instance.wait() + + +@pytest.fixture +def datadir(tmp_path): + def _datadir(data, path=None): + path = path or tmp_path + for k, v in data.items(): + if isinstance(v, dict): + new_path = path / k + new_path.mkdir() + _datadir(v, new_path) + else: + (path / k).write_text(v.decode()) + + return path + return _datadir + + +@pytest.fixture(scope='module') +def servefile_simple(run_servefile, datadir): + data = "NOOT NOOT" + p = datadir({'testfile': data}) / 'testfile' + + run_servefile(str(p)) + + +def download_ok(r, expected_data, expected_code=200): + assert r.status_code == expected_code + assert r.text == expected_data + + +def check_download(expected_data, path='/', host='localhost', port=8080, protocol='http', status_code=200): + url = '{}://{}:{}{}'.format(protocol, host, port, path) + r = requests.get(url, allow_redirects=False) + assert r.status_code == 200 + assert r.text == expected_data + assert r.headers.get('Content-Type') == 'application/octet-stream' + # assert r.headers.get('Content-Disposition') == 'attachment; filename=""' + assert r.headers.get('Content-Transfer-Encoding') == 'binary' + + +def test_version(run_servefile): + s = run_servefile('--version', stderr=subprocess.PIPE) + s.wait() + version = s.stderr.readline().strip() + assert version == 'servefile 0.4.5-unreleased' + + +def test_correct_headers(run_servefile, datadir): + data = "NOOT NOOT" + p = datadir({'testfile': data}) / 'testfile' + run_servefile(str(p)) + r = requests.get("http://127.0.0.1:8080") + assert r.status_code == 200 + assert r.headers.get('Content-Type') == 'application/octet-stream' + assert r.headers.get('Content-Disposition') == 'attachment; filename="testfile"' + assert r.headers.get('Content-Transfer-Encoding') == 'binary' + + +def test_redirect_and_download(run_servefile, datadir): + data = "NOOT NOOT" + p = datadir({'testfile': data}) / 'testfile' + + run_servefile(str(p)) + + r = requests.get("http://127.0.0.1:8080", allow_redirects=False) + assert r.status_code == 302 + assert r.headers.get('Location') == '/testfile' + + r = requests.get("http://127.0.0.1:8080") + download_ok(r, data) + + +def test_specify_port(run_servefile, datadir): + data = "NOOT NOOT" + p = datadir({'testfile': data}) / 'testfile' + run_servefile([str(p), '-p', '8081']) + r = requests.get("http://127.0.0.1:8081") + download_ok(r, data) + + +def test_big_download(run_servefile, datadir): + # test with about 10 mb of data + data = "x" * (10 * 1024 ** 2) + p = datadir({'testfile': data}) / 'testfile' + + run_servefile(str(p)) + r = requests.get("http://127.0.0.1:8080") + download_ok(r, data) + + +def test_authentication(run_servefile, datadir): + data = "NOOT NOOT" + p = datadir({'testfile': data}) / 'testfile' + + run_servefile([str(p), '-a', 'user:password']) + for auth in [('foo', 'bar'), ('user', 'wrong'), ('unknown', 'password')]: + r = requests.get('http://127.0.0.1:8080', auth=auth) + assert '401 - Unauthorized' in r.text + assert r.status_code == 401 + + r = requests.get("http://127.0.0.1:8080", auth=('user', 'password')) + download_ok(r, data) + + +def test_serve_directory(run_servefile, datadir): + d = { + 'foo': {'1': 'cat', '2': 'kitteh', '3': 'wheee'}, + 'bar': {'thisisaverylongfilenamefortestingthatthisstillworksproperly': 'jup!'}, + 'noot': 'still data in here', + 'bigfile': 'x' * (10 * 1024 ** 2), + } + p = datadir(d) + run_servefile([str(p), '-l']) + + # check if all files are in directory listing + # (could be made more sophisticated with beautifulsoup) + for path in '/', '/../': + r = requests.get("http://127.0.0.1:8080" + path) + for k in d: + assert k in r.text + + # download + check_download('cat', '/foo/1') + check_download('kitteh', '/foo/2') + check_download('jup!', '/bar/thisisaverylongfilenamefortestingthatthisstillworksproperly') + + +class Foo: + def noot(servefile_simple): + diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..0160c41 --- /dev/null +++ b/tox.ini @@ -0,0 +1,8 @@ +[tox] +envlist = py27,py36 + +[testenv] +deps = + pytest + requests +commands = pytest --tb=short