Commit 4a5d4811 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Split test site build and start for delayed starting

parent 05347fad
Loading
Loading
Loading
Loading
+60 −23
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@ from os import environ
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Iterator
from typing import NamedTuple
from typing import TypeVar

from behave_utils import URL
@@ -97,23 +96,32 @@ class Nginx(Container):
		)


class Site(NamedTuple):
class Site:
	"""
	A named-tuple of information about the containers for a site fixture
	Manage all the containers of a site fixture
	"""

	url: str
	address: IPv4Address
	frontend: Nginx
	backend: Wordpress
	database: Mysql

	if TYPE_CHECKING:
		T = TypeVar("T", bound="Site")

	def __init__(
		self,
		url: URL,
		network: Network,
		frontend: Nginx,
		backend: Wordpress,
		database: Mysql,
	):
		self.url = url
		self.network = network
		self.frontend = frontend
		self.backend = backend
		self.database = database
		self._address: IPv4Address|None = None

	@classmethod
	@contextmanager
def test_cluster(site_url: URL) -> Iterator[Site]:
	"""
	Configure and start all the necessary containers for use as test fixtures
	"""
	def build(cls: type[T], site_url: URL) -> Iterator[T]:
		test_dir = Path(__file__).parent
		db_init = test_dir / "mysql-init.sql"

@@ -122,10 +130,39 @@ def test_cluster(site_url: URL) -> Iterator[Site]:
			database.start()  # Get a head start on initialising the database
			backend = Wordpress(site_url, database, network=network)
			frontend = Nginx(backend, network=network)
			yield cls(site_url, network, frontend, backend, database)

	@contextmanager
	def running(self) -> Iterator[None]:
		"""
		Start all the services and configure the network
		"""
		with self.database.started(), self.backend.started(), self.frontend.started():
			try:
				yield
			finally:
				self._address = None

		with database.started(), backend.started(), frontend.started():
			addr = frontend.inspect().path(
				f"$.NetworkSettings.Networks.{network}.IPAddress",
	@property
	def address(self) -> IPv4Address:
		if self._address is None:
			if not self.frontend.is_running():
				raise RuntimeError(
					"Site.address may only be accessed inside a Site.running() context",
				)
			self._address = self.frontend.inspect().path(
				f"$.NetworkSettings.Networks.{self.network}.IPAddress",
				str, IPv4Address,
			)
			yield Site(site_url, addr, frontend, backend, database)
		return self._address


@contextmanager
def test_cluster(site_url: URL) -> Iterator[Site]:
	"""
	Configure and start all the necessary containers for use as test fixtures

	Deprecated: this is now a wrapper around Site.build() and Site.running()
	"""
	with Site.build(site_url) as site, site.running():
		yield site