mirror of
https://github.com/logos-storage/bittorrent-benchmarks.git
synced 2026-08-11 08:13:34 +00:00
fix experiment synchronizer, run container as root, add Makefile
This commit is contained in:
parent
7fe9dafe50
commit
8605cce688
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.pyc
|
||||
.idea
|
||||
/volume/deluge*
|
||||
/volume/deluge*
|
||||
*.timestamp
|
||||
62
Makefile
Normal file
62
Makefile
Normal file
@ -0,0 +1,62 @@
|
||||
SHELL := bash
|
||||
|
||||
.SHELLFLAGS := -eu -o pipefail -c
|
||||
|
||||
.PHONY: test-unit-local \
|
||||
start-local-integration-harness \
|
||||
stop-local-integration-harness \
|
||||
test-integration-local \
|
||||
test-all-local \
|
||||
test-unit-docker \
|
||||
test-integration-docker \
|
||||
clean
|
||||
|
||||
# Runs the unit tests locally.
|
||||
unit:
|
||||
poetry run pytest -m "not integration"
|
||||
|
||||
# Starts the local integration harness. This is required for running pytest with the "integration" marker.
|
||||
harness-start:
|
||||
rm -rf ${PWD}/volume/deluge-{1,2,3}
|
||||
docker compose -f docker-compose.local.yaml up
|
||||
|
||||
# Stops the local integration harness.
|
||||
harness-stop:
|
||||
docker compose -f docker-compose.local.yaml down --volumes --remove-orphans
|
||||
|
||||
# Runs the integration tests locally. This requires the integration harness to be running.
|
||||
integration:
|
||||
echo "NOTE: Make sure to have started the integration harness or this will not work"
|
||||
poetry run pytest -m "integration"
|
||||
|
||||
tests: unit integration
|
||||
|
||||
docker/.lastbuilt-test.timestamp: docker/bittorrent-benchmarks.Dockerfile
|
||||
docker build -t bittorrent-benchmarks:test -f ./docker/bittorrent-benchmarks.Dockerfile .
|
||||
touch docker/.lastbuilt-test.timestamp
|
||||
|
||||
docker/.lastbuilt-release.timestamp: docker/bittorrent-benchmarks.Dockerfile
|
||||
docker build -t bittorrent-benchmarks:test --build-arg BUILD_TYPE="release" \
|
||||
-f ./docker/bittorrent-benchmarks.Dockerfile .
|
||||
touch docker/.lastbuilt-release.timestamp
|
||||
|
||||
# Builds the test image required for local dockerized integration tests.
|
||||
image-test: docker/.lastbuilt-test.timestamp
|
||||
image-release: docker/.lastbuilt-release.timestamp
|
||||
|
||||
# Runs the unit tests in a docker container.
|
||||
unit-docker: image-test
|
||||
docker run --entrypoint poetry --rm bittorrent-benchmarks:test run pytest -m "not integration"
|
||||
|
||||
# Runs the integration tests in a docker container.
|
||||
integration-docker: image-test
|
||||
docker compose -f docker-compose.local.yaml -f docker-compose.ci.yaml down --volumes --remove-orphans
|
||||
docker compose -f docker-compose.local.yaml -f docker-compose.ci.yaml up \
|
||||
--abort-on-container-exit --exit-code-from test-runner
|
||||
|
||||
tests-docker: unit-docker integration-docker
|
||||
|
||||
clean:
|
||||
rm -rf docker/.lastbuilt*
|
||||
rm -rf volume/deluge-{1,2,3}
|
||||
docker compose -f docker-compose.local.yaml -f docker-compose.ci.yaml down --volumes --rmi all --remove-orphans
|
||||
@ -3,7 +3,8 @@
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Iterable
|
||||
from typing import Optional
|
||||
from time import time, sleep
|
||||
from typing import Optional, List
|
||||
|
||||
from typing_extensions import Generic, TypeVar
|
||||
|
||||
@ -44,17 +45,30 @@ class ExperimentEnvironment:
|
||||
|
||||
def await_ready(self, timeout: float = 0) -> bool:
|
||||
"""Awaits for all components to be ready, or until a timeout is reached."""
|
||||
# TODO we should probably have per-component timeouts, or at least provide feedback
|
||||
# as to what was the completion state of each component.
|
||||
if not await_predicate(
|
||||
lambda: all(component.is_ready() for component in self.components),
|
||||
timeout=timeout,
|
||||
polling_interval=self.polling_interval,
|
||||
):
|
||||
return False
|
||||
|
||||
start_time = time()
|
||||
not_ready = [component for component in self.components]
|
||||
|
||||
logging.info(f'Awaiting for components to be ready: {self._component_names(not_ready)}')
|
||||
while len(not_ready) != 0:
|
||||
for component in not_ready:
|
||||
if component.is_ready():
|
||||
logger.info(f'Component {str(component)} is ready.')
|
||||
not_ready.remove(component)
|
||||
|
||||
sleep(self.polling_interval)
|
||||
|
||||
if (timeout != 0) and (time() - start_time > timeout):
|
||||
print("timeout")
|
||||
logger.info(f'Some components timed out: {self._component_names(not_ready)}')
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _component_names(components: List[ExperimentComponent]) -> str:
|
||||
return ', '.join(str(component) for component in components)
|
||||
|
||||
def run(self, experiment: Experiment):
|
||||
"""Runs the :class:`Experiment` within this :class:`ExperimentEnvironment`."""
|
||||
if not self.await_ready():
|
||||
|
||||
@ -44,10 +44,12 @@ def test_should_timeout_if_component_takes_too_long():
|
||||
]
|
||||
|
||||
environment = ExperimentEnvironment(components, polling_interval=0)
|
||||
assert not environment.await_ready(0.1)
|
||||
assert not environment.await_ready(0.09)
|
||||
|
||||
assert components[0].iteration == 5
|
||||
assert components[1].iteration < 3
|
||||
# Because ExperimentEnvironment sweeps through the components, it will
|
||||
# iterate exactly once before timing out.
|
||||
assert components[0].iteration == 1
|
||||
assert components[1].iteration == 1
|
||||
|
||||
|
||||
class ExperimentThatReliesOnComponents(Experiment):
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# These have to be wiped out before we boot the containers. Note that this will only work
|
||||
# if you've set up rootless Docker.
|
||||
rm -rf ./volume/{deluge-1,deluge-2,deluge-3}
|
||||
docker compose up
|
||||
@ -14,4 +14,3 @@ touch /opt/bittorrent-benchmarks/volume/.initialized
|
||||
echo "Launching tests."
|
||||
cd /opt/bittorrent-benchmarks
|
||||
poetry run pytest --exitfirst
|
||||
|
||||
|
||||
@ -1,27 +1,22 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
ARG UID=1000
|
||||
ARG GID=1000
|
||||
ARG BUILD_TYPE="test"
|
||||
|
||||
RUN groupadd -g ${GID} runner \
|
||||
&& useradd -u ${UID} -g ${GID} -s /bin/bash -m runner
|
||||
RUN mkdir /opt/bittorrent-benchmarks && chown -R runner:runner /opt/bittorrent-benchmarks
|
||||
RUN pip install poetry
|
||||
|
||||
USER runner
|
||||
RUN mkdir /opt/bittorrent-benchmarks
|
||||
WORKDIR /opt/bittorrent-benchmarks
|
||||
|
||||
COPY --chown=runner:runner pyproject.toml poetry.lock ./
|
||||
RUN if [ "$BUILD_TYPE" = "production" ]; then \
|
||||
echo "Image is a production build"; \
|
||||
COPY pyproject.toml poetry.lock ./
|
||||
RUN if [ "$BUILD_TYPE" = "release" ]; then \
|
||||
echo "Image is a release build"; \
|
||||
poetry install --only main --no-root; \
|
||||
else \
|
||||
echo "Image is a test build"; \
|
||||
poetry install --no-root; \
|
||||
fi
|
||||
|
||||
COPY --chown=runner:runner . .
|
||||
COPY . .
|
||||
RUN poetry install --only main
|
||||
|
||||
ENTRYPOINT ["poetry", "run", "bittorrent-benchmarks", "/opt/bittorrent-benchmarks/experiments.yaml"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user