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:
		| @ -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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         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() |  | ||||||
|             status = container.attrs.get("State", {}).get("Health", {}).get("Status") |  | ||||||
|             if status == "healthy": |  | ||||||
|         return container |         return container | ||||||
|             sleep(1) |  | ||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super().setUp() |         super().setUp() | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens L
					Jens L