mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
* re-instate previously flaky test Signed-off-by: Jens Langhammer <jens@goauthentik.io> * break up big file Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move geoip data to subdir Signed-off-by: Jens Langhammer <jens@goauthentik.io> * i am but a weak man Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix ldap disconnect in testing Signed-off-by: Jens Langhammer <jens@goauthentik.io> * account for mismatched uid due to test server process Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
"""authentik e2e testing utilities"""
|
|
|
|
from time import sleep
|
|
from typing import Any
|
|
from unittest.case import TestCase
|
|
|
|
from docker import DockerClient, from_env
|
|
from docker.errors import DockerException
|
|
from docker.models.containers import Container
|
|
from docker.models.networks import Network
|
|
|
|
from authentik.lib.generators import generate_id
|
|
from authentik.root.test_runner import get_docker_tag
|
|
|
|
|
|
class DockerTestCase(TestCase):
|
|
"""Mixin for dealing with containers"""
|
|
|
|
max_healthcheck_attempts = 45
|
|
|
|
__client: DockerClient
|
|
__network: Network
|
|
|
|
__label_id = generate_id()
|
|
|
|
def setUp(self) -> None:
|
|
self.__client = from_env()
|
|
self.__network = self.docker_client.networks.create(name=f"authentik-test-{generate_id()}")
|
|
|
|
@property
|
|
def docker_client(self) -> DockerClient:
|
|
return self.__client
|
|
|
|
@property
|
|
def docker_network(self) -> Network:
|
|
return self.__network
|
|
|
|
@property
|
|
def docker_labels(self) -> dict[str, str]:
|
|
return {"io.goauthentik.test": self.__label_id}
|
|
|
|
def wait_for_container(self, container: Container) -> Container:
|
|
"""Check that container is health"""
|
|
attempt = 0
|
|
while True:
|
|
container.reload()
|
|
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
if status == "healthy":
|
|
return container
|
|
sleep(1)
|
|
attempt += 1
|
|
if attempt >= self.max_healthcheck_attempts:
|
|
self.output_container_logs(container)
|
|
raise self.failureException("Container failed to start")
|
|
|
|
def get_container_image(self, base: str) -> str:
|
|
"""Try to pull docker image based on git branch, fallback to main if not found."""
|
|
image = f"{base}:gh-main"
|
|
try:
|
|
branch_image = f"{base}:{get_docker_tag()}"
|
|
self.docker_client.images.pull(branch_image)
|
|
return branch_image
|
|
except DockerException:
|
|
self.docker_client.images.pull(image)
|
|
return image
|
|
|
|
def run_container(self, **specs: Any) -> Container:
|
|
if "network_mode" not in specs:
|
|
specs["network"] = self.__network.name
|
|
specs["labels"] = self.docker_labels
|
|
specs["detach"] = True
|
|
if hasattr(self, "live_server_url"):
|
|
specs.setdefault("environment", {})
|
|
specs["environment"]["AUTHENTIK_HOST"] = self.live_server_url
|
|
container: Container = self.docker_client.containers.run(**specs)
|
|
container.reload()
|
|
state = container.attrs.get("State", {})
|
|
if "Health" not in state:
|
|
return container
|
|
self.wait_for_container(container)
|
|
return container
|
|
|
|
def output_container_logs(self, container: Container | None = None) -> None:
|
|
"""Output the container logs to our STDOUT"""
|
|
if not container:
|
|
return
|
|
image = container.image
|
|
if image:
|
|
tags = image.tags[0] if len(image.tags) > 0 else str(image)
|
|
print(f"::group::Container logs - {tags}")
|
|
for log in container.logs().decode().split("\n"):
|
|
print(log)
|
|
print("::endgroup::")
|
|
|
|
def tearDown(self) -> None:
|
|
containers: list[Container] = self.docker_client.containers.list(
|
|
filters={"label": ",".join(f"{x}={y}" for x, y in self.docker_labels.items())}
|
|
)
|
|
for container in containers:
|
|
self.output_container_logs(container)
|
|
try:
|
|
container.kill()
|
|
except DockerException:
|
|
pass
|
|
try:
|
|
container.remove(force=True)
|
|
except DockerException:
|
|
pass
|
|
self.__network.remove()
|