From 0744805aacb08a5407631486b28d10eb8b6dce09 Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:14:39 +0000 Subject: [PATCH 1/6] test: Make use of Sim to speedup test --- pyproject.toml | 1 + .../unit_tests/code_examples/device_module.py | 2 +- tests/unit_tests/core/fake_device_module.py | 28 +++++------ uv.lock | 48 +++++++++++++++++++ 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2f130ef758..91a2c7698d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,7 @@ requires-python = ">=3.11" [dependency-groups] dev = [ + "ophyd_async[sim]", "copier", "myst-parser", "prek", diff --git a/tests/unit_tests/code_examples/device_module.py b/tests/unit_tests/code_examples/device_module.py index a11368d060..bdf3ac828a 100644 --- a/tests/unit_tests/code_examples/device_module.py +++ b/tests/unit_tests/code_examples/device_module.py @@ -2,6 +2,6 @@ from dodal.devices.bimorph_mirror import BimorphMirror -@device_factory() +@device_factory(mock=True) def oav() -> BimorphMirror: return BimorphMirror("BLXXI-BMRPH-01:", number_of_channels=8) diff --git a/tests/unit_tests/core/fake_device_module.py b/tests/unit_tests/core/fake_device_module.py index d496a79845..25b97d2cf1 100644 --- a/tests/unit_tests/core/fake_device_module.py +++ b/tests/unit_tests/core/fake_device_module.py @@ -3,24 +3,24 @@ from dodal.common.beamlines.beamline_utils import device_factory from dodal.utils import OphydV1Device, OphydV2Device from ophyd_async.core import DEFAULT_TIMEOUT, LazyMock, StandardReadable -from ophyd_async.epics.motor import Motor +from ophyd_async.sim import SimMotor def fake_motor_bundle_b( - fake_motor_x: Motor, - fake_motor_y: Motor, -) -> Motor: - return Motor("BAR:", "motor_bundle_b") + fake_motor_x: SimMotor, + fake_motor_y: SimMotor, +) -> SimMotor: + return SimMotor("motor_bundle_b") -def fake_motor_x() -> Motor: - return Motor("FOO:", "motor_x") +def fake_motor_x() -> SimMotor: + return SimMotor("motor_x") class DeviceA(StandardReadable): def __init__(self, name: str = "") -> None: with self.add_children_as_readables(): - self.motor = Motor("X:SIZE") + self.motor = SimMotor("X:SIZE") super().__init__(name) @@ -56,15 +56,15 @@ def ophyd_async_device() -> UnconnectableOphydAsyncDevice: return UnconnectableOphydAsyncDevice(name="ophyd_async_device") -def fake_motor_y() -> Motor: - return Motor("BAZ:", "motor_y") +def fake_motor_y() -> SimMotor: + return SimMotor("motor_y") def fake_motor_bundle_a( - fake_motor_x: Motor, - fake_motor_y: Motor, -) -> Motor: - return Motor("QUX:", "motor_bundle_a") + fake_motor_x: SimMotor, + fake_motor_y: SimMotor, +) -> SimMotor: + return SimMotor("motor_bundle_a") def wrong_return_type() -> int: diff --git a/uv.lock b/uv.lock index 733475a6df..6bc309b2a4 100644 --- a/uv.lock +++ b/uv.lock @@ -452,6 +452,7 @@ dev = [ { name = "jwcrypto" }, { name = "mock" }, { name = "myst-parser" }, + { name = "ophyd-async", extra = ["sim"] }, { name = "prek" }, { name = "pydata-sphinx-theme" }, { name = "pyright" }, @@ -511,6 +512,7 @@ dev = [ { name = "jwcrypto" }, { name = "mock" }, { name = "myst-parser" }, + { name = "ophyd-async", extras = ["sim"] }, { name = "prek" }, { name = "pydata-sphinx-theme", specifier = ">=0.15.4" }, { name = "pyright", specifier = "!=1.1.407" }, @@ -1872,6 +1874,49 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "h5py" +version = "3.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236, upload-time = "2025-10-16T10:35:27.404Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/fd/8349b48b15b47768042cff06ad6e1c229f0a4bd89225bf6b6894fea27e6d/h5py-3.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5aaa330bcbf2830150c50897ea5dcbed30b5b6d56897289846ac5b9e529ec243", size = 3434135, upload-time = "2025-10-16T10:33:47.954Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b0/1c628e26a0b95858f54aba17e1599e7f6cd241727596cc2580b72cb0a9bf/h5py-3.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c970fb80001fffabb0109eaf95116c8e7c0d3ca2de854e0901e8a04c1f098509", size = 2870958, upload-time = "2025-10-16T10:33:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e3/c255cafc9b85e6ea04e2ad1bba1416baa1d7f57fc98a214be1144087690c/h5py-3.15.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80e5bb5b9508d5d9da09f81fd00abbb3f85da8143e56b1585d59bc8ceb1dba8b", size = 4504770, upload-time = "2025-10-16T10:33:54.357Z" }, + { url = "https://files.pythonhosted.org/packages/8b/23/4ab1108e87851ccc69694b03b817d92e142966a6c4abd99e17db77f2c066/h5py-3.15.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b849ba619a066196169763c33f9f0f02e381156d61c03e000bb0100f9950faf", size = 4700329, upload-time = "2025-10-16T10:33:57.616Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e4/932a3a8516e4e475b90969bf250b1924dbe3612a02b897e426613aed68f4/h5py-3.15.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f6c841efd4e6e5b7e82222eaf90819927b6d256ab0f3aca29675601f654f3c", size = 4152456, upload-time = "2025-10-16T10:34:00.843Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0a/f74d589883b13737021b2049ac796328f188dbb60c2ed35b101f5b95a3fc/h5py-3.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ca8a3a22458956ee7b40d8e39c9a9dc01f82933e4c030c964f8b875592f4d831", size = 4617295, upload-time = "2025-10-16T10:34:04.154Z" }, + { url = "https://files.pythonhosted.org/packages/23/95/499b4e56452ef8b6c95a271af0dde08dac4ddb70515a75f346d4f400579b/h5py-3.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:550e51131376889656feec4aff2170efc054a7fe79eb1da3bb92e1625d1ac878", size = 2882129, upload-time = "2025-10-16T10:34:06.886Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bb/cfcc70b8a42222ba3ad4478bcef1791181ea908e2adbd7d53c66395edad5/h5py-3.15.1-cp311-cp311-win_arm64.whl", hash = "sha256:b39239947cb36a819147fc19e86b618dcb0953d1cd969f5ed71fc0de60392427", size = 2477121, upload-time = "2025-10-16T10:34:09.579Z" }, + { url = "https://files.pythonhosted.org/packages/62/b8/c0d9aa013ecfa8b7057946c080c0c07f6fa41e231d2e9bd306a2f8110bdc/h5py-3.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:316dd0f119734f324ca7ed10b5627a2de4ea42cc4dfbcedbee026aaa361c238c", size = 3399089, upload-time = "2025-10-16T10:34:12.135Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5e/3c6f6e0430813c7aefe784d00c6711166f46225f5d229546eb53032c3707/h5py-3.15.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b51469890e58e85d5242e43aab29f5e9c7e526b951caab354f3ded4ac88e7b76", size = 2847803, upload-time = "2025-10-16T10:34:14.564Z" }, + { url = "https://files.pythonhosted.org/packages/00/69/ba36273b888a4a48d78f9268d2aee05787e4438557450a8442946ab8f3ec/h5py-3.15.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a33bfd5dfcea037196f7778534b1ff7e36a7f40a89e648c8f2967292eb6898e", size = 4914884, upload-time = "2025-10-16T10:34:18.452Z" }, + { url = "https://files.pythonhosted.org/packages/3a/30/d1c94066343a98bb2cea40120873193a4fed68c4ad7f8935c11caf74c681/h5py-3.15.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25c8843fec43b2cc368aa15afa1cdf83fc5e17b1c4e10cd3771ef6c39b72e5ce", size = 5109965, upload-time = "2025-10-16T10:34:21.853Z" }, + { url = "https://files.pythonhosted.org/packages/81/3d/d28172116eafc3bc9f5991b3cb3fd2c8a95f5984f50880adfdf991de9087/h5py-3.15.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a308fd8681a864c04423c0324527237a0484e2611e3441f8089fd00ed56a8171", size = 4561870, upload-time = "2025-10-16T10:34:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/a5/83/393a7226024238b0f51965a7156004eaae1fcf84aa4bfecf7e582676271b/h5py-3.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f4a016df3f4a8a14d573b496e4d1964deb380e26031fc85fb40e417e9131888a", size = 5037161, upload-time = "2025-10-16T10:34:30.383Z" }, + { url = "https://files.pythonhosted.org/packages/cf/51/329e7436bf87ca6b0fe06dd0a3795c34bebe4ed8d6c44450a20565d57832/h5py-3.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:59b25cf02411bf12e14f803fef0b80886444c7fe21a5ad17c6a28d3f08098a1e", size = 2874165, upload-time = "2025-10-16T10:34:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/2d02b10a66747c54446e932171dd89b8b4126c0111b440e6bc05a7c852ec/h5py-3.15.1-cp312-cp312-win_arm64.whl", hash = "sha256:61d5a58a9851e01ee61c932bbbb1c98fe20aba0a5674776600fb9a361c0aa652", size = 2458214, upload-time = "2025-10-16T10:34:35.733Z" }, + { url = "https://files.pythonhosted.org/packages/88/b3/40207e0192415cbff7ea1d37b9f24b33f6d38a5a2f5d18a678de78f967ae/h5py-3.15.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c8440fd8bee9500c235ecb7aa1917a0389a2adb80c209fa1cc485bd70e0d94a5", size = 3376511, upload-time = "2025-10-16T10:34:38.596Z" }, + { url = "https://files.pythonhosted.org/packages/31/96/ba99a003c763998035b0de4c299598125df5fc6c9ccf834f152ddd60e0fb/h5py-3.15.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab2219dbc6fcdb6932f76b548e2b16f34a1f52b7666e998157a4dfc02e2c4123", size = 2826143, upload-time = "2025-10-16T10:34:41.342Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c2/fc6375d07ea3962df7afad7d863fe4bde18bb88530678c20d4c90c18de1d/h5py-3.15.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8cb02c3a96255149ed3ac811eeea25b655d959c6dd5ce702c9a95ff11859eb5", size = 4908316, upload-time = "2025-10-16T10:34:44.619Z" }, + { url = "https://files.pythonhosted.org/packages/d9/69/4402ea66272dacc10b298cca18ed73e1c0791ff2ae9ed218d3859f9698ac/h5py-3.15.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:121b2b7a4c1915d63737483b7bff14ef253020f617c2fb2811f67a4bed9ac5e8", size = 5103710, upload-time = "2025-10-16T10:34:48.639Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f6/11f1e2432d57d71322c02a97a5567829a75f223a8c821764a0e71a65cde8/h5py-3.15.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59b0d63b318bf3cc06687def2b45afd75926bbc006f7b8cd2b1a231299fc8599", size = 4556042, upload-time = "2025-10-16T10:34:51.841Z" }, + { url = "https://files.pythonhosted.org/packages/18/88/3eda3ef16bfe7a7dbc3d8d6836bbaa7986feb5ff091395e140dc13927bcc/h5py-3.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e02fe77a03f652500d8bff288cbf3675f742fc0411f5a628fa37116507dc7cc0", size = 5030639, upload-time = "2025-10-16T10:34:55.257Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ea/fbb258a98863f99befb10ed727152b4ae659f322e1d9c0576f8a62754e81/h5py-3.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:dea78b092fd80a083563ed79a3171258d4a4d307492e7cf8b2313d464c82ba52", size = 2864363, upload-time = "2025-10-16T10:34:58.099Z" }, + { url = "https://files.pythonhosted.org/packages/5d/c9/35021cc9cd2b2915a7da3026e3d77a05bed1144a414ff840953b33937fb9/h5py-3.15.1-cp313-cp313-win_arm64.whl", hash = "sha256:c256254a8a81e2bddc0d376e23e2a6d2dc8a1e8a2261835ed8c1281a0744cd97", size = 2449570, upload-time = "2025-10-16T10:35:00.473Z" }, + { url = "https://files.pythonhosted.org/packages/a0/2c/926eba1514e4d2e47d0e9eb16c784e717d8b066398ccfca9b283917b1bfb/h5py-3.15.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5f4fb0567eb8517c3ecd6b3c02c4f4e9da220c8932604960fd04e24ee1254763", size = 3380368, upload-time = "2025-10-16T10:35:03.117Z" }, + { url = "https://files.pythonhosted.org/packages/65/4b/d715ed454d3baa5f6ae1d30b7eca4c7a1c1084f6a2edead9e801a1541d62/h5py-3.15.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:954e480433e82d3872503104f9b285d369048c3a788b2b1a00e53d1c47c98dd2", size = 2833793, upload-time = "2025-10-16T10:35:05.623Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d4/ef386c28e4579314610a8bffebbee3b69295b0237bc967340b7c653c6c10/h5py-3.15.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd125c131889ebbef0849f4a0e29cf363b48aba42f228d08b4079913b576bb3a", size = 4903199, upload-time = "2025-10-16T10:35:08.972Z" }, + { url = "https://files.pythonhosted.org/packages/33/5d/65c619e195e0b5e54ea5a95c1bb600c8ff8715e0d09676e4cce56d89f492/h5py-3.15.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28a20e1a4082a479b3d7db2169f3a5034af010b90842e75ebbf2e9e49eb4183e", size = 5097224, upload-time = "2025-10-16T10:35:12.808Z" }, + { url = "https://files.pythonhosted.org/packages/30/30/5273218400bf2da01609e1292f562c94b461fcb73c7a9e27fdadd43abc0a/h5py-3.15.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa8df5267f545b4946df8ca0d93d23382191018e4cda2deda4c2cedf9a010e13", size = 4551207, upload-time = "2025-10-16T10:35:16.24Z" }, + { url = "https://files.pythonhosted.org/packages/d3/39/a7ef948ddf4d1c556b0b2b9559534777bccc318543b3f5a1efdf6b556c9c/h5py-3.15.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99d374a21f7321a4c6ab327c4ab23bd925ad69821aeb53a1e75dd809d19f67fa", size = 5025426, upload-time = "2025-10-16T10:35:19.831Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d8/7368679b8df6925b8415f9dcc9ab1dab01ddc384d2b2c24aac9191bd9ceb/h5py-3.15.1-cp314-cp314-win_amd64.whl", hash = "sha256:9c73d1d7cdb97d5b17ae385153472ce118bed607e43be11e9a9deefaa54e0734", size = 2865704, upload-time = "2025-10-16T10:35:22.658Z" }, + { url = "https://files.pythonhosted.org/packages/d3/b7/4a806f85d62c20157e62e58e03b27513dc9c55499768530acc4f4c5ce4be/h5py-3.15.1-cp314-cp314-win_arm64.whl", hash = "sha256:a6d8c5a05a76aca9a494b4c53ce8a9c29023b7f64f625c6ce1841e92a362ccdf", size = 2465544, upload-time = "2025-10-16T10:35:25.695Z" }, +] + [[package]] name = "hiredis" version = "3.3.0" @@ -3303,6 +3348,9 @@ ca = [ pva = [ { name = "p4p" }, ] +sim = [ + { name = "h5py" }, +] [[package]] name = "orderly-set" From d014b237e758254429768d55e8c9df49e49f32c2 Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:55:18 +0000 Subject: [PATCH 2/6] test: Add test timeout to max of 60 seconds --- pyproject.toml | 2 ++ uv.lock | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 91a2c7698d..55864ffe9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ dev = [ "pytest-cov", "pytest-asyncio", "pytest-httpx>=0.35.0", + "pytest-timeout", "responses", "ruff", "semver", @@ -103,6 +104,7 @@ filterwarnings = ["error", "ignore::DeprecationWarning"] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" asyncio_mode = "auto" +timeout = 60 [tool.coverage.run] patch = ["subprocess"] diff --git a/uv.lock b/uv.lock index 6bc309b2a4..2ef3cb5a6c 100644 --- a/uv.lock +++ b/uv.lock @@ -460,6 +460,7 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-httpx" }, + { name = "pytest-timeout" }, { name = "responses" }, { name = "respx" }, { name = "ruff" }, @@ -520,6 +521,7 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, + { name = "pytest-timeout" }, { name = "responses" }, { name = "respx" }, { name = "ruff" }, @@ -4266,6 +4268,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e2/d2/1eb1ea9c84f0d2033eb0b49675afdc71aa4ea801b74615f00f3c33b725e3/pytest_httpx-0.36.0-py3-none-any.whl", hash = "sha256:bd4c120bb80e142df856e825ec9f17981effb84d159f9fa29ed97e2357c3a9c8", size = 20229, upload-time = "2025-12-02T16:34:56.45Z" }, ] +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" From 7f2448bed463a887bd09569351736effe7556966 Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:17:57 +0000 Subject: [PATCH 3/6] change timeout to 1 second --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 55864ffe9f..8be28bff36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,7 +104,7 @@ filterwarnings = ["error", "ignore::DeprecationWarning"] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" asyncio_mode = "auto" -timeout = 60 +timeout = 1 [tool.coverage.run] patch = ["subprocess"] From e71eea1be71bb6c4e424f713fef0f9e889635663 Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:27:30 +0000 Subject: [PATCH 4/6] update timeouts --- pyproject.toml | 5 +- test-output | 859 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 862 insertions(+), 2 deletions(-) create mode 100644 test-output diff --git a/pyproject.toml b/pyproject.toml index 8be28bff36..f48a9eddde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ dev = [ "jwcrypto", "deepdiff", "tiled[minimal-server]>=0.2.4", # For system-test of dls.py - "respx" + "respx", ] [project.scripts] @@ -104,7 +104,7 @@ filterwarnings = ["error", "ignore::DeprecationWarning"] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" asyncio_mode = "auto" -timeout = 1 +timeout = 3 [tool.coverage.run] patch = ["subprocess"] @@ -180,6 +180,7 @@ commands = [ "term", "--cov-report", "xml:cov.xml", + "--session-timeout=60", { replace = "posargs", default = [ ], extend = true }, ], diff --git a/test-output b/test-output new file mode 100644 index 0000000000..daad3afa62 --- /dev/null +++ b/test-output @@ -0,0 +1,859 @@ +============================= test session starts ============================== +platform linux -- Python 3.11.9, pytest-9.0.2, pluggy-1.6.0 -- /home/zoheb/workspace/blueapi/.venv/bin/python +cachedir: .pytest_cache +rootdir: /home/zoheb/workspace/blueapi +configfile: pyproject.toml +plugins: anyio-4.12.1, cov-7.0.0, httpx-0.36.0, asyncio-1.3.0, zarr-3.1.5, respx-0.22.0 +asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function +collecting ... collected 844 items + +tests/unit_tests/cli/test_cli.py::test_cli_version PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_main_no_params PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_runs_with_umask_002[serve] PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_runs_with_umask_002[setup-scratch] PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_connection_error_caught_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_authentication_error_caught_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_remote_error_raised_by_wrapper_func PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_get_plans PASSED [ 0%] +tests/unit_tests/cli/test_cli.py::test_get_devices PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_invalid_config_path_handling PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_options_via_env PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_invalid_config_via_env PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_submit_plan PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_submit_plan_without_stomp PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result0-False-Plan succeeded\n] PASSED [ 1%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result1-False-Plan succeeded: 32\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result2-False-Plan returned unserializable result of type 'CustomType'\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_feedback[result3-True-Plan failed: ValueError: Error with value\n] PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_run_plan_background_without_stomp PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_invalid_stomp_config_for_listener PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_cannot_run_plans_without_stomp_config PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_cannot_start_a_plan_without_an_instrument_session PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_can_pass_an_instrument_session_with_an_environment_variable PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_valid_stomp_config_for_listener PASSED [ 2%] +tests/unit_tests/cli/test_cli.py::test_get_env PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_get_state PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_reset_env_client_behavior PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_env_timeout PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_env_reload_server_side_error PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[unknown_plan] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[unauthorised_access] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[invalid_parameters] PASSED [ 3%] +tests/unit_tests/cli/test_cli.py::test_error_handling[remote_control] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_error_handling[value_error] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_run_task_parsing_errors[{-Parameters are not valid JSON] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_run_task_parsing_errors[[]-Parameters must be a JSON object with string keys] PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_device_output_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_plan_output_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_event_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_unknown_object_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_dict_formatting PASSED [ 4%] +tests/unit_tests/cli/test_cli.py::test_generic_base_model_formatting PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_init_scratch_calls_setup_scratch PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_success PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_token_login_with_valid_token PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_with_refresh_token PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_when_cached_token_decode_fails PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_login_with_unauthenticated_server PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_logout_success PASSED [ 5%] +tests/unit_tests/cli/test_cli.py::test_logout_invalid_token PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_logout_unknown_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_logout_when_no_cache PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_local_cache_cleared_on_logout_when_oidc_unavailable PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_wrapper_is_a_directory_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_wrapper_permission_error PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_get_python_environment PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_get_python_env_with_empty_response PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_python_env_output_formatting PASSED [ 6%] +tests/unit_tests/cli/test_cli.py::test_config_schema[True-True] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[True-False] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[False-True] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_config_schema[False-False] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[value0-result0] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[{}-result1] PASSED [ 7%] +tests/unit_tests/cli/test_cli.py::test_task_parameter_type[None-None] PASSED [ 7%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_installs_path PASSED [ 7%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_file PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_nonexistant_path PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[1] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[2] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_scratch_install_fails_on_non_zero_exit_code[65536] PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_not_cloned_and_validated_if_found_locally PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_cloned_if_not_found_locally PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_cloned_with_correct_umask PASSED [ 8%] +tests/unit_tests/cli/test_scratch.py::test_repo_discovery_errors_if_file_found_with_repo_name PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_cloned_repo_changes_to_new_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_existing_repo_changes_to_existing_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_existing_repo_changes_to_new_branch PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_nonexistant_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_non_directory_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_non_sgid_root PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_passes_without_required_gid PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_wrong_gid PASSED [ 9%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_fails_on_blueapi_included PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_succeeds_on_required_gid SKIPPED to be broken in GH actions at the moment. We should +rewrite these tests to use mocks. + +See +https://github.com/DiamondLightSource/blueapi/issues/770) [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_iterates_repos PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_setup_scratch_continues_after_failure PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_python_env_returns_correct_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_fetch_python_env_with_identical_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_fetch_installed_packages_details_returns_correct_packages PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_python_env_filters_by_name_and_source PASSED [ 10%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_name PASSED [ 11%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_empty_if_no_pyproject PASSED [ 11%] +tests/unit_tests/cli/test_scratch.py::test_get_project_name_from_pyproject_returns_empty_if_no_name_key PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_client_from_config PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_plans PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_plan PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_nonexistant_plan PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_devices PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_device PASSED [ 11%] +tests/unit_tests/client/test_client.py::test_get_nonexistent_device PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_child_device PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_state_property PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_state PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_active_task_property PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_get_active_task PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_calls_both_creating_and_starting_endpoints PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_creation_fails PASSED [ 12%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_id_is_wrong PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_fails_if_task_start_fails PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_environment_property PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_get_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_no_timeout PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_with_timeout PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_ignores_current_environment PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_reload_environment_failure PASSED [ 13%] +tests/unit_tests/client/test_client.py::test_abort PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_stop PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_pause PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_resume PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_cannot_run_task_without_message_bus PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_sets_up_control PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_fails_on_failing_event PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event0] PASSED [ 14%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event1] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_calls_event_callback[test_event2] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event0] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event1] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_run_task_ignores_non_matching_events[test_event2] PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_oidc_config_property PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_oidc_config PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_plans_span_ok PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_plan_span_ok PASSED [ 15%] +tests/unit_tests/client/test_client.py::test_get_devices_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_device_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_state_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_active_task_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_create_and_start_task_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_get_environment_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_reload_environment_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_abort_span_ok PASSED [ 16%] +tests/unit_tests/client/test_client.py::test_stop_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_pause_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_resume_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_cannot_run_task_span_ok PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_instrument_session_required PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_setting_instrument_session PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_fluent_instrument_session_setter PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_plan_cache_ignores_underscores PASSED [ 17%] +tests/unit_tests/client/test_client.py::test_plan_cache_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_cache_ignores_underscores PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_devices_are_cached PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_cache_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_repr PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_device_ignores_underscores PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_help_text PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_fallback_help_text PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_properties PASSED [ 18%] +tests/unit_tests/client/test_client.py::test_plan_empty_fallback_help_text PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[required_as_positional] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[required_as_keyword] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_mixed_args_kwargs] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_positional] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_param_mapping[all_as_keyword] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[missing_required] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[duplicate_required] PASSED [ 19%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[duplicate_optional] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[too_many_args] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_plan_invalid_param_mapping[unknown_arg] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_adding_removing_callback PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event0] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event1] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callbacks[test_event2] PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_callback_failures PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_login_existing_login PASSED [ 20%] +tests/unit_tests/client/test_client.py::test_client_new_login PASSED [ 21%] +tests/unit_tests/client/test_client.py::test_client_login_no_oidc PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_context_manager_connects_and_disconnects PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_subscribes_to_all_events PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[0] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[1] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_unsubscribes_on_context_exit[2] PASSED [ 21%] +tests/unit_tests/client/test_event_bus.py::test_client_raises_streaming_error_on_subscribe_failure PASSED [ 21%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[404-KeyError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[401-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[450-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_rest_error_code[500-BlueskyRemoteControlError] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[200-None-None] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[401-None-expected_exception1] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[403-None-expected_exception2] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[404-None-expected_exception3] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[422-{\n "detail": [{\n "loc": ["body", "params", "foo"],\n "type": "missing",\n "msg": "missing value for foo",\n "input": {}\n }]\n }-expected_exception4] PASSED [ 22%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[450-non-standard-expected_exception5] PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_create_task_exceptions[500-internal_error-expected_exception6] PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_auth_request_functionality PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_refresh_if_signature_expired PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_field PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_missing_string PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_extra_string PASSED [ 23%] +tests/unit_tests/client/test_rest.py::test_parameter_error_other_string PASSED [ 23%] +tests/unit_tests/core/test_context.py::test_add_plan[has_no_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan[has_one_param] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan[has_some_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_generated_schema PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_generated_schema_with_generic_bounds PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typeless_param] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typed_and_typeless_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_invalid_plan[has_typeless_params] PASSED [ 24%] +tests/unit_tests/core/test_context.py::test_add_plan_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_only_plans_from_source_module_detected PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_only_plans_from_all_in_module_detected PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_named_device PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_nameless_device PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_nameless_device_without_override PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_override_device_name PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_devices_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_add_failing_deivces_from_module PASSED [ 25%] +tests/unit_tests/core/test_context.py::test_extra_kwargs_in_with_dodal_module_passed_to_make_all_devices PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_with_dodal_module_returns_connection_exceptions PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim_det] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[sim.user_setpoint] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[addr3] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_device[addr4] PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_nonexistent_device PASSED [ 26%] +tests/unit_tests/core/test_context.py::test_lookup_nonexistent_device_child PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_lookup_non_device PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_non_plan PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_non_device PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_devices_and_plans_from_modules_with_config PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_add_metadata_with_config PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_with_config_passes_mock_to_with_dodal_module[True] PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_with_config_passes_mock_to_with_dodal_module[False] PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_function_spec PASSED [ 27%] +tests/unit_tests/core/test_context.py::test_basic_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_device_reference_cache PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_device_reference_cache_with_generics PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_unregister_all_devices PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_generic_reference_type_conversion PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_union PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_new_style_union PASSED [ 28%] +tests/unit_tests/core/test_context.py::test_reference_type_conversion_new_style_optional PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_default_device_reference PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_generic_default_device_reference PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_concrete_type_conversion PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_concrete_method_annotation PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_device_without_protocol_annotation PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_str_default PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_nested_str_default PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_plan_models_not_auto_camelcased PASSED [ 29%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_generic_base PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_multiple_bases PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_generic_bounds_with_no_bases PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[int-int] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[float-float] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[str-str] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[list-list0] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[list-list1] PASSED [ 30%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[dict-dict] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[CustomClass-core.test_context.CustomClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[T-Any] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[GenericClass-core.test_context.GenericClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_qualified_name_with_types[InnerClass-core.test_context.OuterClass.InnerClass] PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_optional_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_overloaded_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_optional_overloaded_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_explicit_none_arg_generated_schema PASSED [ 31%] +tests/unit_tests/core/test_context.py::test_empty_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_single_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_build_error PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_connection_error PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_errors_are_combined PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_mock_passed_to_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_path_provider_passed_to_device_manager PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_device_manager_environment_source PASSED [ 32%] +tests/unit_tests/core/test_context.py::test_non_device_manager_errors PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_without_tiled_not_makes_tiled_inserter PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_default_not_makes_tiled_inserter PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_with_tiled_makes_tiled_inserter[None] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_setup_with_tiled_makes_tiled_inserter[foo] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_instrument_set_for_tiled[None] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_instrument_set_for_tiled[foo] PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_must_have_oidc_config_for_tiled PASSED [ 33%] +tests/unit_tests/core/test_context.py::test_token_url_set_for_tiled PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_publishes_event PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_multi_subscriber PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_can_unsubscribe PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_can_unsubscribe_all PASSED [ 34%] +tests/unit_tests/core/test_event.py::test_correlation_id PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_logout PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_refresh_auth_token PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_no_cache PASSED [ 34%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_refresh_fails PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_invalid_cache PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_get_empty_token_if_exception_in_decode PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_poll_for_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_poll_for_token_timeout PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_server_raises_exception_for_invalid_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_processes_valid_token PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_session_cache_manager_returns_writable_file_path PASSED [ 35%] +tests/unit_tests/service/test_authentication.py::test_tiled_auth_raises_exception PASSED [ 36%] +tests/unit_tests/service/test_authentication.py::test_tiled_auth_sync_auth_flow PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_plans PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_plan PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_devices PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_get_device PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_submit_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_clear_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_begin_task PASSED [ 36%] +tests/unit_tests/service/test_interface.py::test_begin_task_no_task_id PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_tasks_by_status PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_begin_task_with_headers PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_active_task PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_worker_state PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_pause_worker PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_resume_worker PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_cancel_active_task PASSED [ 37%] +tests/unit_tests/service/test_interface.py::test_get_tasks PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_task_by_id[True] PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_task_by_id[False] PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_submit_task_inserts_metadata PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_remove_tiled_subscriber PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_oidc_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_stomp_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_stomp_config_makes_no_client_when_disabled PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_scratch_no_config PASSED [ 38%] +tests/unit_tests/service/test_interface.py::test_get_scratch_with_config PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_configure_numtracker PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_headers_are_cleared PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_numtracker_requires_instrument_metadata PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_without_numtracker_with_existing_provider_does_not_overwrite_provider PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_without_numtracker_without_existing_provider_does_not_make_one PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_with_numtracker_makes_start_document_provider PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_setup_with_numtracker_raises_if_provider_is_defined_in_device_module PASSED [ 39%] +tests/unit_tests/service/test_interface.py::test_numtracker_create_scan_called_with_arguments_from_metadata PASSED [ 40%] +tests/unit_tests/service/test_interface.py::test_update_scan_num_side_effect_sets_data_session_directory_in_re_md PASSED [ 40%] +tests/unit_tests/service/test_interface.py::test_update_scan_num_side_effect_sets_scan_file_in_re_md PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_log_request_details PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers0-expected_headers0] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers1-expected_headers1] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers2-expected_headers2] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers3-expected_headers3] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers4-expected_headers4] PASSED [ 40%] +tests/unit_tests/service/test_main.py::test_get_passthrough_headers[headers5-expected_headers5] PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_generate_schema PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_schema_updated PASSED [ 41%] +tests/unit_tests/service/test_openapi.py::test_schema_version_bump_required PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_rest_config_with_cors_gets_plan PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_rest_config_with_cors PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_plans PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_plan_by_name PASSED [ 41%] +tests/unit_tests/service/test_rest_api.py::test_get_non_existent_plan_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_devices PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_device_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_get_non_existent_device_by_name PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task_inserts_auth_metadata PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_create_task_validation_error PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_put_plan_begins_task PASSED [ 42%] +tests/unit_tests/service/test_rest_api.py::test_put_plan_fails_if_not_idle PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks_by_status PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_tasks_by_status_invalid PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_delete_submitted_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task_active_task_complete PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_set_active_task_worker_already_running PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_task PASSED [ 43%] +tests/unit_tests/service/test_rest_api.py::test_get_all_tasks PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_task_error PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_active_task PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_active_task_none PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_get_state PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_paused PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_paused_to_running PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_aborting PASSED [ 44%] +tests/unit_tests/service/test_rest_api.py::test_set_state_running_to_stopping_including_reason PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_set_state_transition_error PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_set_state_invalid_transition PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_environment_idle PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_delete_environment PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_subprocess_enabled_by_default PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_without_authentication PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_oidc_config_not_found_when_auth_is_disabled PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_oidc_config PASSED [ 45%] +tests/unit_tests/service/test_rest_api.py::test_get_python_environment PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_health_probe PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_docs_redirect PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout_when_oidc_config_invalid[True] PASSED [ 46%] +tests/unit_tests/service/test_rest_api.py::test_logout_when_oidc_config_invalid[False] PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_initialize PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_reload PASSED [ 46%] +tests/unit_tests/service/test_runner.py::test_raises_if_used_before_started PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[None] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[ ] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup[Intentional start_worker exception] PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_can_reload_after_an_error PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_subprocess_enabled_by_default PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_clear_message_for_anonymous_function PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_function_not_findable_on_subprocess PASSED [ 47%] +tests/unit_tests/service/test_runner.py::test_module_not_findable_on_subprocess PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_non_callable_excepts PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_clear_message_for_wrong_return PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_int] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_str] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_list] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_dict] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_simple_model] PASSED [ 48%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_nested_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_unbound_generic_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_accepts_return_type[return_explicitly_bound_generic_model] PASSED [ 49%] +tests/unit_tests/service/test_runner.py::test_run_span_ok PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_defaults[ConfigWithDefaults] PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_defaults[NestedConfigWithDefaults] PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_some_defaults PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_override_all PASSED [ 49%] +tests/unit_tests/test_config.py::test_load_override_all_nested PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_defaultless_schema PASSED [ 50%] +tests/unit_tests/test_config.py::test_inject_values_into_defaultless_schema PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml_nested PASSED [ 50%] +tests/unit_tests/test_config.py::test_load_yaml_override PASSED [ 50%] +tests/unit_tests/test_config.py::test_error_thrown_if_schema_does_not_match_yaml PASSED [ 50%] +tests/unit_tests/test_config.py::test_expand_env_vars PASSED [ 50%] +tests/unit_tests/test_config.py::test_auth_from_env PASSED [ 50%] +tests/unit_tests/test_config.py::test_auth_from_env_repeated_key PASSED [ 51%] +tests/unit_tests/test_config.py::test_auth_from_env_ignore_case PASSED [ 51%] +tests/unit_tests/test_config.py::test_auth_from_env_throws_when_not_available PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed[temp_yaml_config_file1] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed_complete[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_config_yaml_parsed_complete[temp_yaml_config_file1] PASSED [ 51%] +tests/unit_tests/test_config.py::test_raises_validation_error[temp_yaml_config_file0] PASSED [ 51%] +tests/unit_tests/test_config.py::test_oauth_config_model_post_init PASSED [ 52%] +tests/unit_tests/test_config.py::test_extra_fields_are_forbidden_for_application_config PASSED [ 52%] +tests/unit_tests/test_config.py::test_config_schema_updated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_invalid_parameters_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_no_content_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_unauthorised_access_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_unknown_plan_deprecated PASSED [ 52%] +tests/unit_tests/test_deprecation.py::test_missing_stomp_deprecated PASSED [ 52%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_module-plan_names0] PASSED [ 52%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_docstrings-plan_names1] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[plan_metadata-plan_names2] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_plan_module_is_detectable[deferred_plans-plan_names3] PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_example_device_module_is_detectable PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_count_parameter_model_example_is_accurate PASSED [ 53%] +tests/unit_tests/test_example_code.py::test_invalid_plan_args_are_invalid PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[stomp.yaml] PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[scratch.yaml] PASSED [ 53%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[client_auth.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[client.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[numtracker.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[plan_functions.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[graylog.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_config_is_valid[plans_and_devices.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_helm_is_valid[scratch-pv.yaml] PASSED [ 54%] +tests/unit_tests/test_example_config.py::test_example_helm_is_valid[scratch-k8s.yaml] PASSED [ 54%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config0] PASSED [ 54%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config1] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config2] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_config_map[worker_config3] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_init_config_map[values0] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_creates_init_config_map[values1] PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_init_container_spec_generated PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_init_container_spec_disablable PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_helm_chart_does_not_render_arbitrary_rabbitmq_password PASSED [ 55%] +tests/unit_tests/test_helm_chart.py::test_container_gets_container_resources PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[http://0.0.0.0-80] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[http://0.0.0.0:8001-8001] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0-443] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0:9090/path-9090] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[https://0.0.0.0:9000-9000] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_container_port_set[None-8000] PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_init_container_gets_container_resources_by_default PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_init_container_resources_overridable PASSED [ 56%] +tests/unit_tests/test_helm_chart.py::test_worker_scratch_config_used_when_init_container_enabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_fluentd_ignore_true_when_graylog_enabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_fluentd_ignore_false_when_graylog_disabled PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_exists_conditions[True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_exists_conditions[False] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-None-True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-None-False] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-foo-True] PASSED [ 57%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[True-foo-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-None-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-None-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-foo-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_scratch_mount[False-foo-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-None-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-None-False] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-foo-True] PASSED [ 58%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[True-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-None-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-None-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-foo-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_init_config_mount[False-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-None-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-None-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-foo-True] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[True-foo-False] PASSED [ 59%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-None-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-None-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-foo-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_init_container_venv_volume_mount[False-foo-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-True-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-True-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-False-True] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-None-False-False] PASSED [ 60%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-True-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-False-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[True-foo-False-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-True-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-False-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-None-False-False] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-True-True] PASSED [ 61%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-True-False] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-False-True] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_persistent_volume_claim_exists[False-foo-False-False] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[0] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1000] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[1001] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_ldap_account_sync_exists_for_non_default_user[None] PASSED [ 62%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-True-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-False-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-None-False-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-True-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-False-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[True-foo-False-False] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-True-True] PASSED [ 63%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-True-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-False-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-None-False-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-True-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-True-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-False-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_scratch_mount[False-foo-False-False] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-True-True] PASSED [ 64%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-False-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-None-False-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-True-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-False-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[True-foo-False-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-True-True] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-True-False] PASSED [ 65%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-False-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-None-False-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-True-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-True-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-False-True] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_venv_volume_mount[False-foo-False-False] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[0] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1] PASSED [ 66%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1000] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[1001] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_home_and_nslcd_volume_mounts[None] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[True-True] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[True-False] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[False-True] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_main_container_args[False-False] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[True-None] PASSED [ 67%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[True-foo] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[False-None] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_uses_correct_name[False-foo] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-True-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-True-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-False-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-None-False-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-True-True] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-True-False] PASSED [ 68%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-False-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[True-foo-False-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-True-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-True-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-False-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-None-False-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-True-True] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-True-False] PASSED [ 69%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_worker_config_volume_declared[False-foo-False-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-True-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-True-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-None-False-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-True-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-True-False] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-False-True] PASSED [ 70%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[True-foo-False-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-True-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-True-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-False-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-None-False-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-True-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-True-False] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-False-True] PASSED [ 71%] +tests/unit_tests/test_helm_chart.py::test_init_config_and_venv_volumes_declared[False-foo-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-True-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-True-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-False-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-None-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-True-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-True-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-False-True] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[True-foo-False-False] PASSED [ 72%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-True-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-True-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-False-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-None-False-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-True-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-True-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-False-True] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_volume_declared[False-foo-False-False] PASSED [ 73%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-True-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-True-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-False-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-None-False-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-True-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-True-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-False-True] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[True-foo-False-False] PASSED [ 74%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-True-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-True-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-False-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-None-False-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-True-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-True-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-False-True] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_scratch_host_volume_declared[False-foo-False-False] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[0] PASSED [ 75%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1000] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[1001] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_home_and_nslcd_volumes_declared[None] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_init_container_config_copied_from_worker_when_enabled PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[LoadBalancer-80] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[LoadBalancer-800] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[ClusterIP-80] PASSED [ 76%] +tests/unit_tests/test_helm_chart.py::test_service_created[ClusterIP-800] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-LoadBalancer-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-LoadBalancer-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-ClusterIP-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[80-ClusterIP-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-LoadBalancer-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-LoadBalancer-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-ClusterIP-blueapi.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_created[800-ClusterIP-ixx.diamond.ac.uk] PASSED [ 77%] +tests/unit_tests/test_helm_chart.py::test_ingress_not_created PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0:800-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[http://0.0.0.0:800-800] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0:800-80] PASSED [ 78%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[https://0.0.0.0:800-800] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[None-80] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_service_linked_to_api[None-800] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-added_mounts0] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-added_mounts1] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes0-None] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-added_mounts0] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-added_mounts1] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[added_volumes1-None] PASSED [ 79%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-added_mounts0] PASSED [ 80%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-added_mounts1] PASSED [ 80%] +tests/unit_tests/test_helm_chart.py::test_volumes_created[None-None] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 80%] +tests/unit_tests/test_log.py::test_loggers_emits_to_all_handlers[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_logger_does_not_emit_to_graylog[blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 81%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_beamline[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 82%] +tests/unit_tests/test_log.py::test_messages_are_tagged_with_instrument[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 82%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger0] PASSED [ 82%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit--library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger0] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi-library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger0] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger1] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.logging.StreamHandler.emit-blueapi.test-library_logger2] PASSED [ 83%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit--library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi-library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger0] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger1] PASSED [ 84%] +tests/unit_tests/test_log.py::test_library_logger_intergrations[blueapi.log.GELFTCPHandler.emit-blueapi.test-library_logger2] PASSED [ 84%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_adds_filter[blueapi.test] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_plan_tag_filter_context_removes_filter[blueapi.test] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-blueapi] PASSED [ 85%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.logging.StreamHandler.emit-blueapi.test] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-blueapi] PASSED [ 86%] +tests/unit_tests/test_log.py::test_filter_tags_plan_name[blueapi.log.GELFTCPHandler.emit-blueapi.test] PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_debug PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_info PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_warning PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_error PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_critical PASSED [ 86%] +tests/unit_tests/test_log.py::TestColorFormatter::test_other PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345-1-{"proposal": 12345, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345-111-{"proposal": 12345, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cv12345-1-{"proposal": 12345, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345678-1-{"proposal": 12345678, "visit": 1, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cm12345678-111-{"proposal": 12345678, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex[cv12345678-111-{"proposal": 12345678, "visit": 111, "beamline": "ixx"}] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[abc12345-1] PASSED [ 87%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345--1_0] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345--1_1] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345\xa31] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345-1g] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12345g-1] PASSED [ 88%] +tests/unit_tests/utils/test_access_blob.py::test_access_blob_regex_errors[ab12g345-1] PASSED [ 88%] +tests/unit_tests/utils/test_base_model.py::test_snake_case_constructor PASSED [ 88%] +tests/unit_tests/utils/test_deprecated.py::test_deprecated_annotation PASSED [ 88%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100600 (-rw-------)] PASSED [ 88%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100777 (-rwxrwxrwx)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100000 (----------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100644 (-rw-r--r--)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100400 (-r--------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100666 (-rw-rw-rw-)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[100444 (-r--r--r--)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040777 (drwxrwxrwx)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040000 (d---------)] PASSED [ 89%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_disabled[040600 (drw-------)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102777 (-rwxrwsrwx)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102000 (------S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102644 (-rw-r-Sr--)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102600 (-rw---S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102400 (-r----S---)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102666 (-rw-rwSrw-)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[102444 (-r--r-Sr--)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042777 (drwxrwsrwx)] PASSED [ 90%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042000 (d-----S---)] PASSED [ 91%] +tests/unit_tests/utils/test_file_permissions.py::test_is_sgid_set_should_be_enabled[042600 (drw---S---)] PASSED [ 91%] +tests/unit_tests/utils/test_file_permissions.py::test_get_owner_gid PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_imports_all PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_imports_everything_without_all PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_source_is_in_module PASSED [ 91%] +tests/unit_tests/utils/test_modules.py::test_source_is_not_in_module PASSED [ 91%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan PASSED [ 91%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_400_error PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_500_error PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_key_error_on_incorrectly_formatted_responses PASSED [ 92%] +tests/unit_tests/utils/test_numtracker.py::test_create_scan_raises_runtime_error_on_graphql_error PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_with_default_template_returns_correct_path_info PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_with_custom_template_returns_correct_path_info PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_fails_with_missing_instrument PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_fails_with_missing_scan_id PASSED [ 92%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_sets_data_session_directory_default_to_tmp PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_start_called_with_different_document_skips PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_stop_called_with_different_document_skips PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_nested_runs_use_info_from_last_start_doc PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_called_without_start_raises PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_start_document_path_provider_run_stop_called_out_of_order_raises PASSED [ 93%] +tests/unit_tests/utils/test_path_provider.py::test_error_if_template_missing PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_no_print_if_no_errors PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_prints_errors PASSED [ 93%] +tests/unit_tests/utils/test_thread_exception.py::test_passes_args_and_kwargs PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_doesnt_hang PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_is_idempotent_if_worker_not_started PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_multi_stop PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_restart PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_multi_start PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_submit_multiple_tasks PASSED [ 94%] +tests/unit_tests/worker/test_task_worker.py::test_stop_with_task_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_restart_leaves_task_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_submit_before_start_pending PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_clear_task PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_clear_nonexistent_task PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_does_not_allow_simultaneous_running_tasks PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_blocks_until_current_task_set PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_uses_plan_name_filter PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[None-None-NoneType] PASSED [ 95%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[42-42-int] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[helloWorld-helloWorld-str] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result3-serial3-ComplexReturn] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result4-serial4-ModelReturn] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_result_serialized[result5-None-Unreturnable] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_plan_failure_recorded_in_active_task PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_task_not_run_twice PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[0] PASSED [ 96%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[1] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_produces_worker_events[2] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_full_queue_raises PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_metadata_passed_to_context PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_worker_and_data_events_produce_in_order PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[RUNNING-expected_task_ids0] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[PENDING-expected_task_ids1] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_get_tasks_by_status[COMPLETE-expected_task_ids2] PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_submitting_completed_task_fails PASSED [ 97%] +tests/unit_tests/worker/test_task_worker.py::test_start_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_stop_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_submit_task_with_correlation_id PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_clear_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_begin_task_span_ok PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_injected_devices_are_found PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_injected_devices_plan_model PASSED [ 98%] +tests/unit_tests/worker/test_task_worker.py::test_missing_injected_devices_fail_early PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_invalid_injected_devices_fail_early PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_worker_uses_plan_tag_filter_context PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_cycle_without_otel_context PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_devices_are_found PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_devices_plan_model PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_with_pydantic_dataclass PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_injected_composite_with_standard_dataclass PASSED [ 99%] +tests/unit_tests/worker/test_task_worker.py::test_plan_module_with_composite_devices_can_be_loaded_before_device_module PASSED [100%] + +======================= 843 passed, 1 skipped in 20.39s ======================== From eabbf3b8c1637efb25a9530899c03e3e1d813f61 Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:29:08 +0000 Subject: [PATCH 5/6] Use different timeout for system-test --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f48a9eddde..c0126861cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -180,7 +180,7 @@ commands = [ "term", "--cov-report", "xml:cov.xml", - "--session-timeout=60", + "--timeout=60", { replace = "posargs", default = [ ], extend = true }, ], From 009a3981255554f6ace5aff6866d1304b738e2de Mon Sep 17 00:00:00 2001 From: Zoheb Shaikh <26975142+ZohebShaikh@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:38:00 +0000 Subject: [PATCH 6/6] Increase timeout for helm test --- tests/unit_tests/test_example_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit_tests/test_example_config.py b/tests/unit_tests/test_example_config.py index f323cbcb31..5c6c6c742a 100644 --- a/tests/unit_tests/test_example_config.py +++ b/tests/unit_tests/test_example_config.py @@ -21,6 +21,7 @@ def test_example_config_is_valid(file_name: str): loader.load() +@pytest.mark.timeout(30) @pytest.mark.parametrize("file_name", os.listdir(example_helm)) def test_example_helm_is_valid(file_name: str): path = example_helm / file_name