tests: fix potential infinite wait in tests spinning up a container (#7153)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
6d1eef039e
commit
abab635a01
|
@ -17,8 +17,8 @@ TestCase.maxDiff = None
|
||||||
class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||||
"""Runs pytest to discover and run tests."""
|
"""Runs pytest to discover and run tests."""
|
||||||
|
|
||||||
def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(verbosity, failfast, keepdb, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
self.args = []
|
self.args = []
|
||||||
if self.failfast:
|
if self.failfast:
|
||||||
|
@ -47,6 +47,7 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_arguments(cls, parser: ArgumentParser):
|
def add_arguments(cls, parser: ArgumentParser):
|
||||||
"""Add more pytest-specific arguments"""
|
"""Add more pytest-specific arguments"""
|
||||||
|
DiscoverRunner.add_arguments(parser)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--randomly-seed",
|
"--randomly-seed",
|
||||||
type=int,
|
type=int,
|
||||||
|
@ -55,9 +56,6 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||||
"Default behaviour: use random.Random().getrandbits(32), so the seed is"
|
"Default behaviour: use random.Random().getrandbits(32), so the seed is"
|
||||||
"different on each run.",
|
"different on each run.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--keepdb", action="store_true", help="Preserves the test DB between runs."
|
|
||||||
)
|
|
||||||
|
|
||||||
def run_tests(self, test_labels, extra_tests=None, **kwargs):
|
def run_tests(self, test_labels, extra_tests=None, **kwargs):
|
||||||
"""Run pytest and return the exitcode.
|
"""Run pytest and return the exitcode.
|
||||||
|
|
|
@ -49,13 +49,8 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
|
||||||
"OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/",
|
"OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
self.logger.info("Container failed healthcheck")
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
@apply_blueprint(
|
@apply_blueprint(
|
||||||
|
|
|
@ -49,13 +49,8 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
|
||||||
"OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/",
|
"OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
self.logger.info("Container failed healthcheck")
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
@apply_blueprint(
|
@apply_blueprint(
|
||||||
|
|
|
@ -48,13 +48,8 @@ class TestProviderSAML(SeleniumTestCase):
|
||||||
"SP_METADATA_URL": metadata_url,
|
"SP_METADATA_URL": metadata_url,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
self.logger.info("Container failed healthcheck")
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
@apply_blueprint(
|
@apply_blueprint(
|
||||||
|
|
|
@ -43,7 +43,24 @@ def get_docker_tag() -> str:
|
||||||
return f"gh-{branch_name}"
|
return f"gh-{branch_name}"
|
||||||
|
|
||||||
|
|
||||||
class SeleniumTestCase(StaticLiveServerTestCase):
|
class DockerTestCase:
|
||||||
|
"""Mixin for dealing with containers"""
|
||||||
|
|
||||||
|
def wait_for_container(self, 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 >= 30:
|
||||||
|
self.failureException("Container failed to start")
|
||||||
|
|
||||||
|
|
||||||
|
class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
||||||
"""StaticLiveServerTestCase which automatically creates a Webdriver instance"""
|
"""StaticLiveServerTestCase which automatically creates a Webdriver instance"""
|
||||||
|
|
||||||
container: Optional[Container] = None
|
container: Optional[Container] = None
|
||||||
|
@ -82,13 +99,8 @@ class SeleniumTestCase(StaticLiveServerTestCase):
|
||||||
state = container.attrs.get("State", {})
|
state = container.attrs.get("State", {})
|
||||||
if "Health" not in state:
|
if "Health" not in state:
|
||||||
return container
|
return container
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
self.logger.info("Container failed healthcheck")
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
def output_container_logs(self, container: Optional[Container] = None):
|
def output_container_logs(self, container: Optional[Container] = None):
|
||||||
"""Output the container logs to our STDOUT"""
|
"""Output the container logs to our STDOUT"""
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""outpost tests"""
|
"""outpost tests"""
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from channels.testing import ChannelsLiveServerTestCase
|
from channels.testing import ChannelsLiveServerTestCase
|
||||||
|
@ -20,10 +19,10 @@ from authentik.outposts.models import (
|
||||||
)
|
)
|
||||||
from authentik.outposts.tasks import outpost_connection_discovery
|
from authentik.outposts.tasks import outpost_connection_discovery
|
||||||
from authentik.providers.proxy.models import ProxyProvider
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
from tests.e2e.utils import get_docker_tag
|
from tests.e2e.utils import DockerTestCase, get_docker_tag
|
||||||
|
|
||||||
|
|
||||||
class OutpostDockerTests(ChannelsLiveServerTestCase):
|
class OutpostDockerTests(DockerTestCase, ChannelsLiveServerTestCase):
|
||||||
"""Test Docker Controllers"""
|
"""Test Docker Controllers"""
|
||||||
|
|
||||||
def _start_container(self, ssl_folder: str) -> Container:
|
def _start_container(self, ssl_folder: str) -> Container:
|
||||||
|
@ -45,12 +44,8 @@ class OutpostDockerTests(ChannelsLiveServerTestCase):
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""outpost tests"""
|
"""outpost tests"""
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from channels.testing.live import ChannelsLiveServerTestCase
|
from channels.testing.live import ChannelsLiveServerTestCase
|
||||||
|
@ -20,10 +19,10 @@ from authentik.outposts.models import (
|
||||||
from authentik.outposts.tasks import outpost_connection_discovery
|
from authentik.outposts.tasks import outpost_connection_discovery
|
||||||
from authentik.providers.proxy.controllers.docker import DockerController
|
from authentik.providers.proxy.controllers.docker import DockerController
|
||||||
from authentik.providers.proxy.models import ProxyProvider
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
from tests.e2e.utils import get_docker_tag
|
from tests.e2e.utils import DockerTestCase, get_docker_tag
|
||||||
|
|
||||||
|
|
||||||
class TestProxyDocker(ChannelsLiveServerTestCase):
|
class TestProxyDocker(DockerTestCase, ChannelsLiveServerTestCase):
|
||||||
"""Test Docker Controllers"""
|
"""Test Docker Controllers"""
|
||||||
|
|
||||||
def _start_container(self, ssl_folder: str) -> Container:
|
def _start_container(self, ssl_folder: str) -> Container:
|
||||||
|
@ -45,12 +44,8 @@ class TestProxyDocker(ChannelsLiveServerTestCase):
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
while True:
|
self.wait_for_container(container)
|
||||||
container.reload()
|
return container
|
||||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
||||||
if status == "healthy":
|
|
||||||
return container
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
Reference in New Issue