2015-09-17 19:58:22 +02:00
|
|
|
#! /usr/bin/env py.test
|
2015-09-20 19:26:22 +02:00
|
|
|
"""
|
|
|
|
Checks an actual pypi-server against various clients.
|
|
|
|
|
|
|
|
The tests below are using 3 ways to startup pypi-servers:
|
|
|
|
|
2015-12-20 19:33:48 +01:00
|
|
|
- "open": a per-module server instance without any authed operations,
|
2015-09-20 19:26:22 +02:00
|
|
|
serving a single `wheel` package, on a fixed port.
|
2018-06-12 03:27:09 +02:00
|
|
|
- "open": a per-module server instance with authed 'download/upload'
|
|
|
|
operations, serving a single `wheel` package, on a fixed port.
|
2015-09-20 19:26:22 +02:00
|
|
|
- "new_server": starting a new server with any configurations on each test.
|
|
|
|
|
|
|
|
"""
|
2015-09-17 19:58:22 +02:00
|
|
|
import contextlib
|
2020-11-15 22:57:53 +01:00
|
|
|
import itertools
|
2015-09-19 01:02:27 +02:00
|
|
|
import os
|
2020-11-15 22:57:53 +01:00
|
|
|
import shutil
|
|
|
|
import socket
|
2015-09-18 18:31:12 +02:00
|
|
|
import sys
|
2015-09-17 19:58:22 +02:00
|
|
|
import time
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
import typing as t
|
2020-11-15 22:57:53 +01:00
|
|
|
from collections import namedtuple
|
2020-10-08 03:45:51 +02:00
|
|
|
from pathlib import Path
|
2018-06-12 03:27:09 +02:00
|
|
|
from shlex import split
|
|
|
|
from subprocess import Popen
|
2020-11-15 22:57:53 +01:00
|
|
|
from urllib.error import URLError
|
|
|
|
from urllib.request import urlopen
|
2020-10-06 04:04:22 +02:00
|
|
|
|
2015-09-17 19:58:22 +02:00
|
|
|
import pytest
|
|
|
|
|
2018-11-10 01:42:13 +01:00
|
|
|
# ######################################################################
|
|
|
|
# Fixtures & Helper Functions
|
|
|
|
# ######################################################################
|
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
CURRENT_PATH = Path(__file__).parent
|
|
|
|
ports = itertools.count(10000)
|
|
|
|
Srv = namedtuple("Srv", ("port", "root"))
|
2015-09-18 20:20:01 +02:00
|
|
|
|
2018-11-10 01:42:13 +01:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@contextlib.contextmanager
|
|
|
|
def run_server(root, authed=False, other_cli=""):
|
2017-11-14 17:47:27 +01:00
|
|
|
"""Run a server, optionally with partial auth enabled."""
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
htpasswd = (
|
|
|
|
CURRENT_PATH.joinpath("../fixtures/htpasswd.a.a").expanduser().resolve()
|
|
|
|
)
|
2015-09-19 01:02:27 +02:00
|
|
|
pswd_opt_choices = {
|
2020-11-15 22:57:53 +01:00
|
|
|
True: f"-P {htpasswd} -a update,download",
|
2017-11-14 17:47:27 +01:00
|
|
|
False: "-P. -a.",
|
2020-11-15 22:57:53 +01:00
|
|
|
"partial": f"-P {htpasswd} -a update",
|
2015-09-19 01:02:27 +02:00
|
|
|
}
|
2015-09-20 19:26:22 +02:00
|
|
|
pswd_opts = pswd_opt_choices[authed]
|
2020-11-15 22:57:53 +01:00
|
|
|
|
|
|
|
port = next(ports)
|
2019-01-25 00:48:57 +01:00
|
|
|
cmd = (
|
2020-11-15 22:57:53 +01:00
|
|
|
f"{sys.executable} -m pypiserver.__main__ "
|
|
|
|
f"run -vvv --overwrite -i 127.0.0.1 "
|
|
|
|
f"-p {port} {pswd_opts} {other_cli} {root}"
|
2019-01-25 00:48:57 +01:00
|
|
|
)
|
2022-02-20 21:17:20 +01:00
|
|
|
proc = Popen(cmd.split(), bufsize=2**16)
|
2020-11-15 22:57:53 +01:00
|
|
|
srv = Srv(port, root)
|
|
|
|
try:
|
|
|
|
wait_until_ready(srv)
|
|
|
|
assert proc.poll() is None
|
|
|
|
yield srv
|
|
|
|
finally:
|
|
|
|
print(f"Killing {srv}")
|
|
|
|
_kill_proc(proc)
|
|
|
|
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def wait_until_ready(srv: Srv, n_tries=10):
|
|
|
|
for _ in range(n_tries):
|
|
|
|
if is_ready(srv):
|
|
|
|
return True
|
|
|
|
time.sleep(0.5)
|
|
|
|
raise TimeoutError
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def is_ready(srv: Srv):
|
2015-09-17 19:58:22 +02:00
|
|
|
try:
|
2020-11-15 22:57:53 +01:00
|
|
|
return urlopen(build_url(srv.port), timeout=0.5).getcode() in (
|
|
|
|
200,
|
|
|
|
401,
|
|
|
|
)
|
|
|
|
except (URLError, socket.timeout):
|
|
|
|
return False
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def _kill_proc(proc):
|
|
|
|
proc.terminate()
|
2015-09-19 01:02:27 +02:00
|
|
|
try:
|
2020-11-15 22:57:53 +01:00
|
|
|
proc.wait(timeout=1)
|
2015-09-19 01:02:27 +02:00
|
|
|
finally:
|
2020-11-15 22:57:53 +01:00
|
|
|
proc.kill()
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
def build_url(port: t.Union[int, str], user: str = "", pswd: str = "") -> str:
|
2020-11-15 22:57:53 +01:00
|
|
|
auth = f"{user}:{pswd}@" if user or pswd else ""
|
|
|
|
return f"http://{auth}localhost:{port}"
|
2015-09-19 02:36:43 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def run_setup_py(path: Path, arguments: str):
|
|
|
|
return os.system(f"{sys.executable} {path / 'setup.py'} {arguments}")
|
2015-09-20 18:35:11 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
# A test-distribution to check if
|
|
|
|
# bottle supports uploading 100's of packages,
|
|
|
|
# see: https://github.com/pypiserver/pypiserver/issues/82
|
|
|
|
#
|
|
|
|
# Has been run once `pip wheel .`, just to generate:
|
|
|
|
# ./wheelhouse/centodeps-0.0.0-cp34-none-win_amd64.whl
|
|
|
|
#
|
|
|
|
SETUP_PY = """\
|
|
|
|
from setuptools import setup
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
setup(
|
|
|
|
name="centodeps",
|
|
|
|
install_requires=["a==1.0"] * 200,
|
|
|
|
options={
|
|
|
|
"bdist_wheel": {"universal": True},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
"""
|
2015-09-20 19:26:22 +02:00
|
|
|
|
|
|
|
|
2020-10-06 04:04:22 +02:00
|
|
|
@pytest.fixture(scope="module")
|
2020-11-15 22:57:53 +01:00
|
|
|
def project(tmp_path_factory):
|
|
|
|
projdir = tmp_path_factory.mktemp("project") / "centodeps"
|
|
|
|
projdir.mkdir(parents=True, exist_ok=True)
|
|
|
|
projdir.joinpath("setup.py").write_text(SETUP_PY)
|
|
|
|
return projdir
|
|
|
|
|
2015-09-19 02:36:43 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def server_root(tmp_path_factory):
|
|
|
|
return tmp_path_factory.mktemp("root")
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-10-06 04:04:22 +02:00
|
|
|
@pytest.fixture(scope="module")
|
2020-11-15 22:57:53 +01:00
|
|
|
def wheel_file(project, tmp_path_factory):
|
|
|
|
distdir = tmp_path_factory.mktemp("dist")
|
|
|
|
assert run_setup_py(project, f"bdist_wheel -d {distdir}") == 0
|
|
|
|
return list(distdir.glob("centodeps*.whl"))[0]
|
|
|
|
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.fixture()
|
|
|
|
def hosted_wheel_file(wheel_file, server_root):
|
|
|
|
dst = server_root / wheel_file.name
|
|
|
|
shutil.copy(wheel_file, dst)
|
|
|
|
yield dst
|
|
|
|
if dst.is_file():
|
|
|
|
dst.unlink()
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
|
|
|
|
def clear_directory(root: Path):
|
|
|
|
for path in root.iterdir():
|
|
|
|
if path.is_file():
|
|
|
|
path.unlink()
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-10-06 04:04:22 +02:00
|
|
|
@pytest.fixture(scope="module")
|
2020-11-15 22:57:53 +01:00
|
|
|
def _open_server(server_root):
|
|
|
|
with run_server(server_root, authed=False) as srv:
|
|
|
|
yield srv
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def open_server(_open_server: Srv):
|
|
|
|
yield _open_server
|
|
|
|
clear_directory(_open_server.root)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
|
|
def _authed_server(server_root):
|
|
|
|
with run_server(server_root, authed=True) as srv:
|
|
|
|
yield srv
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def authed_server(_authed_server):
|
|
|
|
yield _authed_server
|
|
|
|
clear_directory(_authed_server.root)
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-10-06 04:04:22 +02:00
|
|
|
@pytest.fixture(scope="module")
|
2020-11-15 22:57:53 +01:00
|
|
|
def _partial_auth_server(server_root):
|
|
|
|
with run_server(server_root, authed="partial") as srv:
|
|
|
|
yield srv
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def partial_authed_server(_partial_auth_server):
|
|
|
|
yield _partial_auth_server
|
|
|
|
clear_directory(_partial_auth_server.root)
|
2015-09-17 19:58:22 +02:00
|
|
|
|
|
|
|
|
2015-09-18 20:20:01 +02:00
|
|
|
@pytest.fixture
|
2020-11-15 22:57:53 +01:00
|
|
|
def empty_packdir(tmp_path_factory):
|
|
|
|
return tmp_path_factory.mktemp("dists")
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
def pip_download(
|
|
|
|
cmd: str,
|
|
|
|
port: t.Union[int, str],
|
|
|
|
install_dir: str,
|
|
|
|
user: str = None,
|
|
|
|
pswd: str = None,
|
|
|
|
) -> int:
|
2020-11-15 22:57:53 +01:00
|
|
|
url = build_url(port, user, pswd)
|
|
|
|
return _run_pip(f"-vv download -d {install_dir} -i {url} {cmd}")
|
2015-09-18 19:05:07 +02:00
|
|
|
|
2015-09-17 19:58:22 +02:00
|
|
|
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
def _run_pip(cmd: str) -> int:
|
2018-06-12 03:27:09 +02:00
|
|
|
ncmd = (
|
2019-09-02 21:31:59 +02:00
|
|
|
"pip --no-cache-dir --disable-pip-version-check "
|
2020-10-08 03:45:51 +02:00
|
|
|
f"--retries 0 --timeout 5 --no-input {cmd}"
|
|
|
|
)
|
|
|
|
print(f"PIP: {ncmd}")
|
2018-06-12 03:27:09 +02:00
|
|
|
proc = Popen(split(ncmd))
|
|
|
|
proc.communicate()
|
|
|
|
return proc.returncode
|
2015-09-18 20:20:01 +02:00
|
|
|
|
|
|
|
|
2015-09-19 01:02:27 +02:00
|
|
|
@pytest.fixture
|
2020-11-15 22:57:53 +01:00
|
|
|
def pipdir(tmp_path_factory):
|
|
|
|
return tmp_path_factory.mktemp("pip")
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2018-11-10 01:42:13 +01:00
|
|
|
@contextlib.contextmanager
|
2020-11-15 22:57:53 +01:00
|
|
|
def pypirc_file(repo, username="''", password="''"):
|
|
|
|
pypirc_path = Path.home() / ".pypirc"
|
|
|
|
old_pypirc = pypirc_path.read_text() if pypirc_path.is_file() else None
|
|
|
|
pypirc_path.write_text(
|
2020-10-08 03:45:51 +02:00
|
|
|
"\n".join(
|
|
|
|
(
|
|
|
|
"[distutils]",
|
|
|
|
"index-servers: test",
|
2020-11-15 22:57:53 +01:00
|
|
|
"",
|
|
|
|
"[test]",
|
|
|
|
f"repository: {repo}",
|
|
|
|
f"username: {username}",
|
2020-10-08 03:45:51 +02:00
|
|
|
f"password: {password}",
|
2020-10-06 04:04:22 +02:00
|
|
|
)
|
2018-11-10 01:42:13 +01:00
|
|
|
)
|
2020-10-08 03:45:51 +02:00
|
|
|
)
|
2018-11-10 01:42:13 +01:00
|
|
|
try:
|
2020-11-15 22:57:53 +01:00
|
|
|
yield pypirc_path
|
2018-11-10 01:42:13 +01:00
|
|
|
finally:
|
|
|
|
if old_pypirc:
|
2020-11-15 22:57:53 +01:00
|
|
|
pypirc_path.write_text(old_pypirc)
|
2018-11-10 01:42:13 +01:00
|
|
|
else:
|
2020-11-15 22:57:53 +01:00
|
|
|
pypirc_path.unlink()
|
2018-11-10 01:42:13 +01:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def open_pypirc(open_server):
|
|
|
|
with pypirc_file(repo=build_url(open_server.port)) as path:
|
|
|
|
yield path
|
2018-11-10 01:42:13 +01:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def authed_pypirc(authed_server):
|
|
|
|
username, password = "a", "a"
|
|
|
|
with pypirc_file(
|
|
|
|
repo=build_url(authed_server.port),
|
|
|
|
username=username,
|
|
|
|
password=password,
|
|
|
|
) as path:
|
|
|
|
yield path
|
|
|
|
|
|
|
|
|
Docker improvements (#365)
* Docker improvements
This addresses much of what was brought up in #359. Specifically, it:
- Significantly improves testing for the Docker image, adding a
`docker/test_docker.py` file using the regular pytest machinery to
set up and run docker images for testing
- Hopefully addresses a variety of permissions issues, by being explicit
about what access pypiserver needs and asking for it, only erroring
if that access is not available
- Requires RX permissions on `/data` (R to read files, X to list files
and to be able to cd into the directory. This is important since
`/data` is the `WORKDIR`)
- Requires RWX permissions on `/data/packages`, so that we can list
packages, write packages, and read packages.
- When running in the default configuration (as root on Linux or
as the pypiserver-named rootish user on Mac), with no volumes
mounted, these requirements are all satisfied
- Volume mounts still must be readable by the pypiserver user (UID
9898) in order for the container to run. However, we now error early
if this is not the case, and direct users to a useful issue.
- If the container is run as a non-root, non-pypiserver user (e.g.
because someone ran `docker run --user=<user_id>`, we try to run
pypiserver as that user). Provided that user has access to the
necessary directories, it should run fine.
- Fixes issues with running help and similar commands
- Updates the Docker image to use `PYPISERVER_PORT` for port
specification, while still falling back to `PORT` for backwards
compatibility
- Moves some docker-related things into a `/docker` directory
- Adds a `Makefile` for building a test fixture package sdist and wheel,
so that test code can call `make mypkg` and not need to worry about it
potentially building multiple times
The only issue #359 raises that's not addressed here is the one of
running pypiserver in the Docker container using some non-default server
for performance. I would like to do some benchmarking before deciding on
what to do there.
2021-02-06 18:28:15 +01:00
|
|
|
def run_twine(command: str, package: str, conf: str) -> None:
|
2020-10-06 04:04:22 +02:00
|
|
|
proc = Popen(
|
2020-11-15 22:57:53 +01:00
|
|
|
split(
|
|
|
|
f"twine {command} --repository test --config-file {conf} {package}"
|
2020-10-06 04:04:22 +02:00
|
|
|
)
|
|
|
|
)
|
2018-11-10 01:42:13 +01:00
|
|
|
proc.communicate()
|
2020-11-15 22:57:53 +01:00
|
|
|
assert not proc.returncode, f"Twine {command} failed. See stdout/err"
|
2018-11-10 01:42:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
# ######################################################################
|
|
|
|
# Tests
|
|
|
|
# ######################################################################
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
all_servers = [
|
|
|
|
("open_server", "open_pypirc"),
|
|
|
|
("authed_server", "authed_pypirc"),
|
|
|
|
("partial_authed_server", "authed_pypirc"),
|
|
|
|
]
|
2018-11-10 01:42:13 +01:00
|
|
|
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def test_pip_install_package_not_found(open_server, pipdir):
|
|
|
|
assert pip_download("centodeps", open_server.port, pipdir) != 0
|
|
|
|
assert not list(pipdir.iterdir())
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def test_pip_install_open_succeeds(open_server, hosted_wheel_file, pipdir):
|
|
|
|
assert pip_download("centodeps", open_server.port, pipdir) == 0
|
|
|
|
assert pipdir.joinpath(hosted_wheel_file.name).is_file()
|
2015-09-19 01:02:27 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.mark.usefixtures("wheel_file")
|
|
|
|
def test_pip_install_authed_fails(authed_server, pipdir):
|
|
|
|
assert pip_download("centodeps", authed_server.port, pipdir) != 0
|
|
|
|
assert not list(pipdir.iterdir())
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
|
|
|
|
def test_pip_install_authed_succeeds(authed_server, hosted_wheel_file, pipdir):
|
2020-10-06 04:04:22 +02:00
|
|
|
assert (
|
2020-11-15 22:57:53 +01:00
|
|
|
pip_download(
|
|
|
|
"centodeps", authed_server.port, pipdir, user="a", pswd="a"
|
|
|
|
)
|
2020-10-06 04:04:22 +02:00
|
|
|
== 0
|
|
|
|
)
|
2020-11-15 22:57:53 +01:00
|
|
|
assert pipdir.joinpath(hosted_wheel_file.name).is_file()
|
2015-09-18 20:20:01 +02:00
|
|
|
|
|
|
|
|
2020-10-06 04:04:22 +02:00
|
|
|
@pytest.mark.parametrize("pkg_frmt", ["bdist", "bdist_wheel"])
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.mark.parametrize(["server_fixture", "pypirc_fixture"], all_servers)
|
|
|
|
def test_setuptools_upload(
|
|
|
|
server_fixture, pypirc_fixture, project, pkg_frmt, server_root, request
|
|
|
|
):
|
|
|
|
request.getfixturevalue(server_fixture)
|
|
|
|
request.getfixturevalue(pypirc_fixture)
|
2015-09-20 19:26:22 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
assert len(list(server_root.iterdir())) == 0
|
2015-09-20 19:26:22 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
for i in range(5):
|
|
|
|
print(f"++Attempt #{i}")
|
|
|
|
assert run_setup_py(project, f"-vvv {pkg_frmt} upload -r test") == 0
|
|
|
|
assert len(list(server_root.iterdir())) == 1
|
2015-09-20 19:26:22 +02:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
def test_partial_authed_open_download(partial_authed_server):
|
2017-11-14 17:47:27 +01:00
|
|
|
"""Validate that partial auth still allows downloads."""
|
2020-11-15 22:57:53 +01:00
|
|
|
url = build_url(partial_authed_server.port) + "/simple"
|
|
|
|
resp = urlopen(url)
|
|
|
|
assert resp.getcode() == 200
|
2017-11-14 17:47:27 +01:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.mark.parametrize("hash_algo", ("md5", "sha256", "sha512"))
|
|
|
|
@pytest.mark.usefixtures("hosted_wheel_file")
|
|
|
|
def test_hash_algos(server_root, pipdir, hash_algo):
|
Update Tests for New Twine
* Updated .travis.yml to fix PEP 440 warnings
* Fixed twine calls
We were getting test failures on multiple branches in
`test_server.py`. I first investigated a warning message
popping up in every test run:
```
PEP440Warning,
/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/pkg_resources/__init__.py:2510: PEP440Warning: 'setuptools (git-0.4.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
```
Moving the installation of setuptools, pip, sphinx, and tox
into the `install` key for Travis resolved that issue, but
`test_server.py` tests were still failing. It turns out that
Twine 1.7.0 added support for SSL cert specification and,
in the process, changed the call signature for the `upload`
and `register` internal methods.
This PR fixes the calls so that they align with Twine's new
function signature. Note that tests now fail on Twine <1.7.0,
so I have also updated the dev requirements file.
2016-07-17 20:40:06 +02:00
|
|
|
"""Test twine upload with no authentication"""
|
2020-11-15 22:57:53 +01:00
|
|
|
with run_server(
|
|
|
|
server_root, other_cli="--hash-algo {}".format(hash_algo)
|
|
|
|
) as srv:
|
|
|
|
assert pip_download("centodeps", srv.port, pipdir) == 0
|
2019-09-02 21:31:59 +02:00
|
|
|
|
2015-09-20 18:35:11 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.mark.parametrize(["server_fixture", "pypirc_fixture"], all_servers)
|
|
|
|
def test_twine_upload(
|
|
|
|
server_fixture, pypirc_fixture, server_root, wheel_file, request
|
|
|
|
):
|
2019-09-02 21:31:59 +02:00
|
|
|
"""Test twine upload with no authentication"""
|
2020-11-15 22:57:53 +01:00
|
|
|
assert len(list(server_root.iterdir())) == 0
|
|
|
|
request.getfixturevalue(server_fixture)
|
|
|
|
pypirc = request.getfixturevalue(pypirc_fixture)
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
run_twine("upload", wheel_file, conf=pypirc)
|
2015-09-19 01:02:27 +02:00
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
assert len(list(server_root.iterdir())) == 1
|
|
|
|
assert server_root.joinpath(wheel_file.name).is_file(), (
|
|
|
|
wheel_file.name,
|
|
|
|
list(server_root.iterdir()),
|
|
|
|
)
|
2017-11-14 17:47:27 +01:00
|
|
|
|
|
|
|
|
2020-11-15 22:57:53 +01:00
|
|
|
@pytest.mark.parametrize(["server_fixture", "pypirc_fixture"], all_servers)
|
|
|
|
def test_twine_register(server_fixture, pypirc_fixture, wheel_file, request):
|
Update Tests for New Twine
* Updated .travis.yml to fix PEP 440 warnings
* Fixed twine calls
We were getting test failures on multiple branches in
`test_server.py`. I first investigated a warning message
popping up in every test run:
```
PEP440Warning,
/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/pkg_resources/__init__.py:2510: PEP440Warning: 'setuptools (git-0.4.0)' is being parsed as a legacy, non PEP 440, version. You may find odd behavior and sort order. In particular it will be sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.
```
Moving the installation of setuptools, pip, sphinx, and tox
into the `install` key for Travis resolved that issue, but
`test_server.py` tests were still failing. It turns out that
Twine 1.7.0 added support for SSL cert specification and,
in the process, changed the call signature for the `upload`
and `register` internal methods.
This PR fixes the calls so that they align with Twine's new
function signature. Note that tests now fail on Twine <1.7.0,
so I have also updated the dev requirements file.
2016-07-17 20:40:06 +02:00
|
|
|
"""Test unauthenticated twine registration"""
|
2020-11-15 22:57:53 +01:00
|
|
|
request.getfixturevalue(server_fixture)
|
|
|
|
pypirc = request.getfixturevalue(pypirc_fixture)
|
|
|
|
run_twine("register", wheel_file, conf=pypirc)
|