From a57dfdba857e58b476d638e63a1877e407064057 Mon Sep 17 00:00:00 2001 From: Tomer Nosrati Date: Wed, 25 Oct 2023 21:47:18 +0300 Subject: [PATCH] Added unit tests coverage (#73) * New Tests: tests/unit/api/test_container.py * New Tests: tests/unit/api/test_base.py * New Tests: tests/unit/api/test_backend.py * New Tests: tests/unit/api/test_broker.py * New Tests: tests/unit/api/test_worker.py * New Tests: tests/unit/api/test_setup.py * New Tests: tests/unit/vendors/test_worker.py * New Tests: tests/unit/vendors/test_memcached.py * New Tests: tests/unit/vendors/test_rabbitmq.py * New Tests: tests/unit/vendors/test_redis.py --- src/pytest_celery/api/backend.py | 17 +- src/pytest_celery/api/base.py | 47 +++--- src/pytest_celery/api/broker.py | 17 +- src/pytest_celery/api/container.py | 3 + src/pytest_celery/api/setup.py | 66 ++++---- src/pytest_celery/vendors/worker/container.py | 30 ++-- tests/unit/api/test_backend.py | 20 ++- tests/unit/api/test_base.py | 146 ++++++++++++------ tests/unit/api/test_broker.py | 20 ++- tests/unit/api/test_container.py | 21 +++ tests/unit/api/test_setup.py | 49 ++++-- tests/unit/api/test_worker.py | 27 +++- tests/unit/conftest.py | 13 +- tests/unit/vendors/test_memcached.py | 14 +- tests/unit/vendors/test_rabbitmq.py | 14 +- tests/unit/vendors/test_redis.py | 20 ++- tests/unit/vendors/test_worker.py | 46 +++--- 17 files changed, 383 insertions(+), 187 deletions(-) diff --git a/src/pytest_celery/api/backend.py b/src/pytest_celery/api/backend.py index f24ca541..a26314e4 100644 --- a/src/pytest_celery/api/backend.py +++ b/src/pytest_celery/api/backend.py @@ -5,22 +5,23 @@ from pytest_celery.api.base import CeleryTestCluster from pytest_celery.api.base import CeleryTestNode from pytest_celery.api.container import CeleryTestContainer -from pytest_celery.defaults import WORKER_ENV +from pytest_celery.defaults import DEFAULT_WORKER_ENV class CeleryTestBackend(CeleryTestNode): @classmethod def default_config(cls) -> dict: return { - "url": WORKER_ENV["CELERY_RESULT_BACKEND"], - "local_url": WORKER_ENV["CELERY_RESULT_BACKEND"], + "url": DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"], + "local_url": DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"], } def restart(self) -> None: super().restart() - self.app.conf.update( - result_backend=self.config()["local_url"], - ) + if self.app: + self.app.conf.update( + result_backend=self.config()["local_url"], + ) class CeleryBackendCluster(CeleryTestCluster): @@ -37,6 +38,6 @@ def _set_nodes( @classmethod def default_config(cls) -> dict: return { - "urls": [WORKER_ENV["CELERY_RESULT_BACKEND"]], - "local_urls": [WORKER_ENV["CELERY_RESULT_BACKEND"]], + "urls": [DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"]], + "local_urls": [DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"]], } diff --git a/src/pytest_celery/api/base.py b/src/pytest_celery/api/base.py index 9df8366f..8a1f419e 100644 --- a/src/pytest_celery/api/base.py +++ b/src/pytest_celery/api/base.py @@ -26,20 +26,25 @@ def container(self) -> CeleryTestContainer: def app(self) -> Celery: return self._app - def ready(self) -> bool: - return self.container.ready() - - def config(self, *args: tuple, **kwargs: dict) -> dict: - return self.container.celeryconfig + def __eq__(self, __value: object) -> bool: + if isinstance(__value, CeleryTestNode): + return all( + ( + self.container == __value.container, + self.app == __value.app, + ) + ) + return False @classmethod def default_config(cls) -> dict: return {} - def __eq__(self, __value: object) -> bool: - if isinstance(__value, CeleryTestNode): - return self.container == __value.container - return False + def ready(self) -> bool: + return self.container.ready() + + def config(self, *args: tuple, **kwargs: dict) -> dict: + return self.container.celeryconfig def logs(self) -> str: return self.container.logs() @@ -89,6 +94,14 @@ def __init__(self, *nodes: Tuple[Union[CeleryTestNode, CeleryTestContainer]]) -> self.nodes = nodes # type: ignore + @property + def nodes(self) -> Tuple[CeleryTestNode]: + return self._nodes + + @nodes.setter + def nodes(self, nodes: Tuple[Union[CeleryTestNode, CeleryTestContainer]]) -> None: + self._nodes = self._set_nodes(*nodes) # type: ignore + def __iter__(self) -> Iterator[CeleryTestNode]: return iter(self.nodes) @@ -105,13 +118,9 @@ def __eq__(self, __value: object) -> bool: return False return False - @property - def nodes(self) -> Tuple[CeleryTestNode]: - return self._nodes - - @nodes.setter - def nodes(self, nodes: Tuple[Union[CeleryTestNode, CeleryTestContainer]]) -> None: - self._nodes = self._set_nodes(*nodes) # type: ignore + @classmethod + def default_config(cls) -> dict: + return {} @abstractmethod def _set_nodes( @@ -139,9 +148,7 @@ def config(self, *args: tuple, **kwargs: dict) -> dict: "local_urls": [c["local_url"] for c in config], } - @classmethod - def default_config(cls) -> dict: - return {} - def teardown(self) -> None: + # Do not need to call teardown on the nodes + # but only tear down self pass diff --git a/src/pytest_celery/api/broker.py b/src/pytest_celery/api/broker.py index 131ead67..d8f25002 100644 --- a/src/pytest_celery/api/broker.py +++ b/src/pytest_celery/api/broker.py @@ -5,22 +5,23 @@ from pytest_celery.api.base import CeleryTestCluster from pytest_celery.api.base import CeleryTestNode from pytest_celery.api.container import CeleryTestContainer -from pytest_celery.defaults import WORKER_ENV +from pytest_celery.defaults import DEFAULT_WORKER_ENV class CeleryTestBroker(CeleryTestNode): @classmethod def default_config(cls) -> dict: return { - "url": WORKER_ENV["CELERY_BROKER_URL"], - "local_url": WORKER_ENV["CELERY_BROKER_URL"], + "url": DEFAULT_WORKER_ENV["CELERY_BROKER_URL"], + "local_url": DEFAULT_WORKER_ENV["CELERY_BROKER_URL"], } def restart(self) -> None: super().restart() - self.app.conf.update( - broker_url=self.config()["local_url"], - ) + if self.app: + self.app.conf.update( + broker_url=self.config()["local_url"], + ) class CeleryBrokerCluster(CeleryTestCluster): @@ -37,6 +38,6 @@ def _set_nodes( @classmethod def default_config(cls) -> dict: return { - "urls": [WORKER_ENV["CELERY_BROKER_URL"]], - "local_urls": [WORKER_ENV["CELERY_BROKER_URL"]], + "urls": [DEFAULT_WORKER_ENV["CELERY_BROKER_URL"]], + "local_urls": [DEFAULT_WORKER_ENV["CELERY_BROKER_URL"]], } diff --git a/src/pytest_celery/api/container.py b/src/pytest_celery/api/container.py index a0cafdbe..4747f146 100644 --- a/src/pytest_celery/api/container.py +++ b/src/pytest_celery/api/container.py @@ -31,6 +31,9 @@ def ready_prompt(self) -> Optional[str]: return None def _wait_port(self, port: str) -> int: + if not port: + raise ValueError("Port cannot be empty") + while not super().ready(): pass _, p = self.get_addr(port) diff --git a/src/pytest_celery/api/setup.py b/src/pytest_celery/api/setup.py index 35a2074e..855bae05 100644 --- a/src/pytest_celery/api/setup.py +++ b/src/pytest_celery/api/setup.py @@ -34,12 +34,12 @@ def app(self) -> Celery: return self._app @property - def worker_cluster(self) -> CeleryWorkerCluster: - return self._worker_cluster + def backend_cluster(self) -> CeleryBackendCluster: + return self._backend_cluster @property - def worker(self) -> CeleryTestWorker: - return self._worker_cluster[0] # type: ignore + def backend(self) -> CeleryTestBackend: + return self._backend_cluster[0] # type: ignore @property def broker_cluster(self) -> CeleryBrokerCluster: @@ -50,37 +50,12 @@ def broker(self) -> CeleryTestBroker: return self._broker_cluster[0] # type: ignore @property - def backend_cluster(self) -> CeleryBackendCluster: - return self._backend_cluster + def worker_cluster(self) -> CeleryWorkerCluster: + return self._worker_cluster @property - def backend(self) -> CeleryTestBackend: - return self._backend_cluster[0] # type: ignore - - def ready(self, ping: bool = False, control: bool = False, docker: bool = True) -> bool: - ready = True - - if docker and ready: - ready = all([self.broker_cluster.ready(), self.backend_cluster.ready()]) - ready = ready and self.worker_cluster.ready() - - if control and ready: - r = self.app.control.ping() - ready = ready and all([all([res["ok"] == "pong" for _, res in response.items()]) for response in r]) - - if ping and ready: - # TODO: ignore mypy globally for type overriding - worker: CeleryTestWorker - for worker in self.worker_cluster: # type: ignore - res = self.ping.s().apply_async(queue=worker.worker_queue) - ready = ready and res.get(timeout=RESULT_TIMEOUT) == "pong" - - # Set app for all nodes - nodes = self.broker_cluster.nodes + self.backend_cluster.nodes - for node in nodes: - node._app = self.app - - return ready + def worker(self) -> CeleryTestWorker: + return self._worker_cluster[0] # type: ignore @classmethod def name(cls) -> str: @@ -130,3 +105,28 @@ def chords_allowed(self) -> bool: def teardown(self) -> None: pass + + def ready(self, ping: bool = False, control: bool = False, docker: bool = True) -> bool: + ready = True + + if docker and ready: + ready = all([self.broker_cluster.ready(), self.backend_cluster.ready()]) + ready = ready and self.worker_cluster.ready() + + if control and ready: + r = self.app.control.ping() + ready = ready and all([all([res["ok"] == "pong" for _, res in response.items()]) for response in r]) + + if ping and ready: + # TODO: ignore mypy globally for type overriding + worker: CeleryTestWorker + for worker in self.worker_cluster: # type: ignore + res = self.ping.s().apply_async(queue=worker.worker_queue) + ready = ready and res.get(timeout=RESULT_TIMEOUT) == "pong" + + # Set app for all nodes + nodes = self.broker_cluster.nodes + self.backend_cluster.nodes + for node in nodes: + node._app = self.app + + return ready diff --git a/src/pytest_celery/vendors/worker/container.py b/src/pytest_celery/vendors/worker/container.py index 89c1965b..b15745ae 100644 --- a/src/pytest_celery/vendors/worker/container.py +++ b/src/pytest_celery/vendors/worker/container.py @@ -13,6 +13,13 @@ class CeleryWorkerContainer(CeleryTestContainer): + def _wait_port(self, port: str) -> int: + raise NotImplementedError + + @property + def ready_prompt(self) -> str: + return "ready." + @classmethod def version(cls) -> str: return DEFAULT_WORKER_VERSION @@ -29,6 +36,14 @@ def worker_name(cls) -> str: def worker_queue(cls) -> str: return DEFAULT_WORKER_QUEUE + @classmethod + def tasks_modules(cls) -> set: + return set() + + @classmethod + def signals_modules(cls) -> set: + return set() + @classmethod def buildargs(cls) -> dict: return { @@ -145,18 +160,3 @@ def _initial_content_worker_signals(cls, worker_signals: set) -> dict: else: print("No signals found") return initial_content - - @classmethod - def tasks_modules(cls) -> set: - return set() - - @classmethod - def signals_modules(cls) -> set: - return set() - - def _wait_port(self, port: str) -> int: - raise NotImplementedError - - @property - def ready_prompt(self) -> str: - return "ready." diff --git a/tests/unit/api/test_backend.py b/tests/unit/api/test_backend.py index 44f31bcd..ece24d55 100644 --- a/tests/unit/api/test_backend.py +++ b/tests/unit/api/test_backend.py @@ -1,8 +1,10 @@ import pytest +from celery import Celery from pytest_lazyfixture import lazy_fixture from pytest_celery import CELERY_BACKEND from pytest_celery import CELERY_BACKEND_CLUSTER +from pytest_celery import DEFAULT_WORKER_ENV from pytest_celery import CeleryBackendCluster from pytest_celery import CeleryTestBackend @@ -10,12 +12,22 @@ @pytest.mark.parametrize("backend", [lazy_fixture(CELERY_BACKEND)]) class test_celey_test_backend: def test_default_config_format(self, backend: CeleryTestBackend): - expected_format = {"url", "local_url"} - assert set(backend.default_config().keys()) == expected_format + assert backend.default_config()["url"] == DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"] + assert backend.default_config()["local_url"] == DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"] + + def test_restart_no_app(self, backend: CeleryTestBackend): + assert backend.app is None + backend.restart() + + def test_restart_with_app(self, backend: CeleryTestBackend, celery_setup_app: Celery): + backend._app = celery_setup_app + assert "result_backend" not in celery_setup_app.conf.changes + backend.restart() + assert "result_backend" in celery_setup_app.conf.changes @pytest.mark.parametrize("cluster", [lazy_fixture(CELERY_BACKEND_CLUSTER)]) class test_celery_backend_cluster: def test_default_config_format(self, cluster: CeleryBackendCluster): - expected_format = {"urls", "local_urls"} - assert set(cluster.default_config().keys()) == expected_format + assert cluster.default_config()["urls"] == [DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"]] + assert cluster.default_config()["local_urls"] == [DEFAULT_WORKER_ENV["CELERY_RESULT_BACKEND"]] diff --git a/tests/unit/api/test_base.py b/tests/unit/api/test_base.py index a9d6bf97..caf26a43 100644 --- a/tests/unit/api/test_base.py +++ b/tests/unit/api/test_base.py @@ -2,22 +2,18 @@ from unittest.mock import patch import pytest +import pytest_docker_tools from celery import Celery from pytest_celery import CeleryTestCluster from pytest_celery import CeleryTestContainer from pytest_celery import CeleryTestNode +from tests.unit.conftest import mocked_container @pytest.fixture def mocked_test_container() -> CeleryTestContainer: - return Mock(spec=CeleryTestContainer) - - -@pytest.fixture(autouse=True) -def mock_wait_for_callable(): - with patch("pytest_celery.api.base.wait_for_callable", new=Mock()): - yield + return mocked_container(CeleryTestContainer) class test_celery_test_node: @@ -25,63 +21,127 @@ class test_celery_test_node: def node(self, mocked_test_container: CeleryTestContainer): return CeleryTestNode(mocked_test_container) - def test_app(self, mocked_test_container: CeleryTestContainer): - expected_app = Celery() - node = CeleryTestNode(mocked_test_container, expected_app) - assert node.app is expected_app + class test_constructor: + def test_app(self, mocked_test_container: CeleryTestContainer): + expected_app = Celery() + node = CeleryTestNode(mocked_test_container, expected_app) + assert node.app is expected_app - def test_default_config_format(self, mocked_test_container: CeleryTestContainer): - node = CeleryTestNode(mocked_test_container) - assert node.default_config() == dict() + def test_eq_opertor_eq(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + node2 = CeleryTestNode(mocked_test_container) + assert node1 == node2 + assert node1 is not node2 - def test_eq_opertor(self, mocked_test_container: CeleryTestContainer): - node1 = CeleryTestNode(mocked_test_container) - node2 = CeleryTestNode(mocked_test_container) - assert node1 == node2 - assert node1 is not node2 + def test_eq_opertor_not_eq(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + node2 = CeleryTestNode(mocked_container(CeleryTestContainer)) + assert node1 != node2 + assert node1 is not node2 + + def test_container(self, node: CeleryTestNode): + assert node.container is not None + + def test_app(self, node: CeleryTestNode): + assert node.app is None + + def test_default_config(self, node: CeleryTestNode): + assert node.default_config() == dict() def test_ready(self, node: CeleryTestNode): assert node.ready() + def test_config(self, node: CeleryTestNode): + assert node.config() + + def test_logs(self, node: CeleryTestNode): + assert node.logs() + + def test_name(self, node: CeleryTestNode): + assert node.name() + + def test_hostname(self, node: CeleryTestNode): + assert node.hostname() + + def test_kill(self, node: CeleryTestNode): + node.kill() + + def test_restart(self, node: CeleryTestNode): + node.restart() + + def test_teardown(self, node: CeleryTestNode): + node.teardown() + def test_wait_for_log(self, node: CeleryTestNode): node.wait_for_log("", "test_celey_test_worker.test_wait_for_log") def test_assert_log_exists(self, node: CeleryTestNode): node.assert_log_exists("", "test_celey_test_worker.test_assert_log_exists") + def test_assert_log_exists_assertion_error(self, node: CeleryTestNode): + with patch("pytest_celery.api.base.wait_for_callable", new=Mock()) as mocked_wait_for_callable: + mocked_wait_for_callable.side_effect = pytest_docker_tools.exceptions.TimeoutError + with pytest.raises(AssertionError): + node.assert_log_exists("", "test_celey_test_worker.test_assert_log_exists_assertion_error") + + def test_assert_log_does_not_exist(self, node: CeleryTestNode): + with patch("pytest_celery.api.base.wait_for_callable", new=Mock()) as mocked_wait_for_callable: + mocked_wait_for_callable.side_effect = pytest_docker_tools.exceptions.TimeoutError + node.assert_log_does_not_exist("", "test_celey_test_worker.test_assert_log_does_not_exist") + + def test_assert_log_does_not_exist_assertion_error(self, node: CeleryTestNode): + with pytest.raises(AssertionError): + node.assert_log_does_not_exist("", "test_celey_test_worker.test_assert_log_does_not_exist_assertion_error") + class test_celery_test_cluster: @pytest.fixture def cluster(self, mocked_test_container: CeleryTestContainer): - local_test_container = Mock(spec=CeleryTestContainer) + local_test_container = mocked_container(CeleryTestContainer) node1 = CeleryTestNode(mocked_test_container) node2 = CeleryTestNode(local_test_container) return CeleryTestCluster(node1, node2) - def test_set_nodes(self, mocked_test_container: CeleryTestContainer): - node1 = CeleryTestNode(mocked_test_container) - node2 = CeleryTestNode(mocked_test_container) - cluster = CeleryTestCluster(node1) - cluster._set_nodes(node2) - assert cluster[0] == node2 - - def test_iter(self, mocked_test_container: CeleryTestContainer): - node1 = CeleryTestNode(mocked_test_container) - cluster = CeleryTestCluster(node1) - assert list(cluster) == [node1] - - def test_len(self, mocked_test_container: CeleryTestContainer): - node1 = CeleryTestNode(mocked_test_container) - cluster = CeleryTestCluster(node1) - assert len(cluster) == 1 - - def test_getitem(self, mocked_test_container: CeleryTestContainer): - node1 = CeleryTestNode(mocked_test_container) - cluster = CeleryTestCluster(node1) - assert cluster[0] == node1 + class test_constructor: + def test_set_nodes(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + node2 = CeleryTestNode(mocked_test_container) + cluster = CeleryTestCluster(node1) + cluster._set_nodes(node2) + assert cluster[0] == node2 + + def test_iter(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + cluster = CeleryTestCluster(node1) + assert list(cluster) == [node1] + + def test_len(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + cluster = CeleryTestCluster(node1) + assert len(cluster) == 1 + + def test_getitem(self, mocked_test_container: CeleryTestContainer): + node1 = CeleryTestNode(mocked_test_container) + cluster = CeleryTestCluster(node1) + assert cluster[0] == node1 + + def test_nodes_getter(self, cluster: CeleryTestCluster): + assert cluster.nodes + + def test_nodes_setter(self, cluster: CeleryTestCluster, mocked_test_container: CeleryTestContainer): + cluster.nodes = cluster.nodes + (mocked_test_container,) + assert cluster.nodes[-1].container == mocked_test_container + cluster.nodes = (mocked_test_container,) + assert cluster[0].container == mocked_test_container + + def test_default_config(self, cluster: CeleryTestCluster): + assert cluster.default_config() == dict() def test_ready(self, cluster: CeleryTestCluster): assert cluster.ready() - def test_default_config_format(self, cluster: CeleryTestCluster): - assert cluster.default_config() == dict() + def test_config(self, cluster: CeleryTestCluster): + assert cluster.config() + + def test_teardown(self, cluster: CeleryTestCluster): + cluster.teardown() diff --git a/tests/unit/api/test_broker.py b/tests/unit/api/test_broker.py index e97a8175..c6110f20 100644 --- a/tests/unit/api/test_broker.py +++ b/tests/unit/api/test_broker.py @@ -1,8 +1,10 @@ import pytest +from celery import Celery from pytest_lazyfixture import lazy_fixture from pytest_celery import CELERY_BROKER from pytest_celery import CELERY_BROKER_CLUSTER +from pytest_celery import DEFAULT_WORKER_ENV from pytest_celery import CeleryBrokerCluster from pytest_celery import CeleryTestBroker @@ -10,12 +12,22 @@ @pytest.mark.parametrize("broker", [lazy_fixture(CELERY_BROKER)]) class test_celey_test_broker: def test_default_config_format(self, broker: CeleryTestBroker): - expected_format = {"url", "local_url"} - assert set(broker.default_config().keys()) == expected_format + assert broker.default_config()["url"] == DEFAULT_WORKER_ENV["CELERY_BROKER_URL"] + assert broker.default_config()["local_url"] == DEFAULT_WORKER_ENV["CELERY_BROKER_URL"] + + def test_restart_no_app(self, broker: CeleryTestBroker): + assert broker.app is None + broker.restart() + + def test_restart_with_app(self, broker: CeleryTestBroker, celery_setup_app: Celery): + broker._app = celery_setup_app + assert "broker_url" not in celery_setup_app.conf.changes + broker.restart() + assert "broker_url" in celery_setup_app.conf.changes @pytest.mark.parametrize("cluster", [lazy_fixture(CELERY_BROKER_CLUSTER)]) class test_celery_broker_cluster: def test_default_config_format(self, cluster: CeleryBrokerCluster): - expected_format = {"urls", "local_urls"} - assert set(cluster.default_config().keys()) == expected_format + assert cluster.default_config()["urls"] == [DEFAULT_WORKER_ENV["CELERY_BROKER_URL"]] + assert cluster.default_config()["local_urls"] == [DEFAULT_WORKER_ENV["CELERY_BROKER_URL"]] diff --git a/tests/unit/api/test_container.py b/tests/unit/api/test_container.py index 4cf52020..ab22a80c 100644 --- a/tests/unit/api/test_container.py +++ b/tests/unit/api/test_container.py @@ -15,3 +15,24 @@ class test_celery_test_container: def test_client(self, mocked_container: CeleryTestContainer): with pytest.raises(NotImplementedError): mocked_container.client + + def test_celeryconfig(self, mocked_container: CeleryTestContainer): + with pytest.raises(NotImplementedError): + mocked_container.celeryconfig + + def test_command(self, mocked_container: CeleryTestContainer): + with pytest.raises(NotImplementedError): + mocked_container.command() + + def test_teardown(self, mocked_container: CeleryTestContainer): + mocked_container.teardown() + + def test_ready_prompt(self, mocked_container: CeleryTestContainer): + assert mocked_container.ready_prompt is None + + def test_wait_port(self, mocked_container: CeleryTestContainer): + with pytest.raises(ValueError): + mocked_container._wait_port(None) + + def test_wait_ready(self, mocked_container: CeleryTestContainer): + assert mocked_container._wait_ready() diff --git a/tests/unit/api/test_setup.py b/tests/unit/api/test_setup.py index 35d42ad7..14451303 100644 --- a/tests/unit/api/test_setup.py +++ b/tests/unit/api/test_setup.py @@ -1,3 +1,4 @@ +import pytest from celery import Celery from pytest_celery import CeleryTestBackend @@ -7,20 +8,23 @@ class test_celery_test_setup_unit: - def test_setup_has_worker_cluster(self, celery_setup: CeleryTestSetup, celery_worker: CeleryTestWorker): - assert len(celery_setup.worker_cluster) == 1 - assert celery_worker in celery_setup.worker_cluster + def test_setup_app(self, celery_setup: CeleryTestSetup): + assert isinstance(celery_setup.app, Celery) - def test_setup_has_broker_cluster(self, celery_setup: CeleryTestSetup, celery_broker: CeleryTestBroker): - assert len(celery_setup.broker_cluster) == 1 - assert celery_broker in celery_setup.broker_cluster + def test_setup_has_app(self, celery_setup: CeleryTestSetup, celery_setup_app: Celery): + assert celery_setup.app == celery_setup_app def test_setup_has_backend_cluster(self, celery_setup: CeleryTestSetup, celery_backend: CeleryTestBackend): assert len(celery_setup.backend_cluster) == 1 assert celery_backend in celery_setup.backend_cluster - def test_setup_has_app(self, celery_setup: CeleryTestSetup, celery_setup_app: Celery): - assert celery_setup.app == celery_setup_app + def test_setup_has_broker_cluster(self, celery_setup: CeleryTestSetup, celery_broker: CeleryTestBroker): + assert len(celery_setup.broker_cluster) == 1 + assert celery_broker in celery_setup.broker_cluster + + def test_setup_has_worker_cluster(self, celery_setup: CeleryTestSetup, celery_worker: CeleryTestWorker): + assert len(celery_setup.worker_cluster) == 1 + assert celery_worker in celery_setup.worker_cluster def test_setup_has_name(self, celery_setup: CeleryTestSetup): assert celery_setup.name() @@ -29,5 +33,30 @@ def test_setup_config_format(self, celery_setup: CeleryTestSetup, celery_worker_ expected_format = {"broker_url", "result_backend"} assert set(celery_setup.config(celery_worker_cluster_config).keys()) == expected_format - def test_setup_app(self, celery_setup: CeleryTestSetup): - assert isinstance(celery_setup.app, Celery) + def test_update_app_config(self, celery_setup: CeleryTestSetup, celery_setup_app: Celery): + celery_setup.update_app_config(celery_setup_app) + + def test_create_setup_app(self, celery_setup: CeleryTestSetup, celery_setup_config: dict): + celery_setup.create_setup_app(celery_setup_config, celery_setup.name()) + + def test_create_setup_app_no_config(self, celery_setup: CeleryTestSetup): + with pytest.raises(ValueError): + celery_setup.create_setup_app({}, celery_setup.name()) + + def test_create_setup_app_no_name(self, celery_setup: CeleryTestSetup, celery_setup_config: dict): + with pytest.raises(ValueError): + celery_setup.create_setup_app(celery_setup_config, "") + + def test_teardown(self, celery_setup: CeleryTestSetup): + celery_setup.teardown() + + def test_default_ready_args(self, celery_setup: CeleryTestSetup): + assert celery_setup.ready() + + def test_ping_ready(self, celery_setup: CeleryTestSetup): + celery_setup.worker_cluster.nodes = tuple() + assert celery_setup.ready(ping=True, control=False, docker=False) + + def test_docker_ready(self, celery_setup: CeleryTestSetup): + celery_setup.worker_cluster.nodes = tuple() + assert celery_setup.ready(ping=False, control=False, docker=True) diff --git a/tests/unit/api/test_worker.py b/tests/unit/api/test_worker.py index bec0df0f..82a75bf8 100644 --- a/tests/unit/api/test_worker.py +++ b/tests/unit/api/test_worker.py @@ -4,24 +4,39 @@ from pytest_celery import CELERY_WORKER from pytest_celery import CELERY_WORKER_CLUSTER -from pytest_celery import DEFAULT_WORKER_VERSION from pytest_celery import CeleryTestWorker from pytest_celery import CeleryWorkerCluster @pytest.mark.parametrize("worker", [lazy_fixture(CELERY_WORKER)]) class test_celey_test_worker: - def test_ready(self, worker: CeleryTestWorker): - assert worker.ready() - worker.container.ready.assert_called_once() + def test_app(self, worker: CeleryTestWorker, celery_setup_app: Celery): + assert worker.app is celery_setup_app + + def test_version(self, worker: CeleryTestWorker): + worker.version + worker.container.version.assert_called_once() + + def test_log_level(self, worker: CeleryTestWorker): + worker.log_level + worker.container.log_level.assert_called_once() + + def test_worker_name(self, worker: CeleryTestWorker): + worker.worker_name + worker.container.worker_name.assert_called_once() + + def test_worker_queue(self, worker: CeleryTestWorker): + worker.worker_queue + worker.container.worker_queue.assert_called_once() @pytest.mark.parametrize("cluster", [lazy_fixture(CELERY_WORKER_CLUSTER)]) class test_celery_worker_cluster: def test_app(self, cluster: CeleryWorkerCluster, celery_setup_app: Celery): - node: CeleryTestWorker for node in cluster: assert node.app is celery_setup_app def test_versions(self, cluster: CeleryWorkerCluster): - assert cluster.versions == {DEFAULT_WORKER_VERSION} + cluster.versions + for node in cluster: + node.container.version.assert_called_once() diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 34f91cd9..812a55bc 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -1,5 +1,6 @@ from typing import Type from unittest.mock import Mock +from unittest.mock import patch import pytest @@ -9,8 +10,16 @@ from pytest_celery import RedisContainer +@pytest.fixture(autouse=True) +def mock_wait_for_callable(): + with patch("pytest_celery.api.base.wait_for_callable", new=Mock()): + with patch("pytest_celery.api.container.wait_for_callable", new=Mock()): + yield + + def mocked_container(spec: Type) -> Mock: mocked_container = Mock(spec=spec) + mocked_container.id = "mocked_test_container_id" mocked_container.celeryconfig = { "url": "mocked_url", "local_url": "mocked_local_url", @@ -40,6 +49,4 @@ def default_redis_broker() -> RedisContainer: @pytest.fixture def default_worker_container() -> CeleryWorkerContainer: - m = mocked_container(CeleryWorkerContainer) - m.version.return_value = CeleryWorkerContainer.version() - return m + return mocked_container(CeleryWorkerContainer) diff --git a/tests/unit/vendors/test_memcached.py b/tests/unit/vendors/test_memcached.py index 4088bf05..d012176b 100644 --- a/tests/unit/vendors/test_memcached.py +++ b/tests/unit/vendors/test_memcached.py @@ -4,6 +4,7 @@ from pytest_celery import CELERY_MEMCACHED_BACKEND from pytest_celery import MEMCACHED_ENV from pytest_celery import MEMCACHED_IMAGE +from pytest_celery import MEMCACHED_PORTS from pytest_celery import MemcachedContainer from pytest_celery import MemcachedTestBackend @@ -18,9 +19,16 @@ def test_env(self): def test_image(self): assert MemcachedContainer.image() == MEMCACHED_IMAGE + def test_ports(self): + assert MemcachedContainer.ports() == MEMCACHED_PORTS + @pytest.mark.parametrize("backend", [lazy_fixture(CELERY_MEMCACHED_BACKEND)]) class test_memcached_backend_api: - def test_ready(self, backend: MemcachedTestBackend): - backend.ready() - backend.container.ready.assert_called_once() + @pytest.mark.skip(reason="Placeholder") + def test_placeholder(self, backend: MemcachedTestBackend): + # The class MemcachedTestBackend is currently a placeholder + # so we don't have any specific tests for it yet. + # This test suite is pre-configured to test the MemcachedTestBackend + # and ready to be used once the class is implemented. + pass diff --git a/tests/unit/vendors/test_rabbitmq.py b/tests/unit/vendors/test_rabbitmq.py index a60b1ec9..8a929310 100644 --- a/tests/unit/vendors/test_rabbitmq.py +++ b/tests/unit/vendors/test_rabbitmq.py @@ -4,6 +4,7 @@ from pytest_celery import CELERY_RABBITMQ_BROKER from pytest_celery import RABBITMQ_ENV from pytest_celery import RABBITMQ_IMAGE +from pytest_celery import RABBITMQ_PORTS from pytest_celery import RabbitMQContainer from pytest_celery import RabbitMQTestBroker @@ -19,9 +20,16 @@ def test_env(self): def test_image(self): assert RabbitMQContainer.image() == RABBITMQ_IMAGE + def test_ports(self): + assert RabbitMQContainer.ports() == RABBITMQ_PORTS + @pytest.mark.parametrize("broker", [lazy_fixture(CELERY_RABBITMQ_BROKER)]) class test_rabbitmq_broker_api: - def test_ready(self, broker: RabbitMQTestBroker): - broker.ready() - broker.container.ready.assert_called_once() + @pytest.mark.skip(reason="Placeholder") + def test_placeholder(self, broker: RabbitMQTestBroker): + # The class RabbitMQTestBroker is currently a placeholder + # so we don't have any specific tests for it yet. + # This test suite is pre-configured to test the RabbitMQTestBroker + # and ready to be used once the class is implemented. + pass diff --git a/tests/unit/vendors/test_redis.py b/tests/unit/vendors/test_redis.py index ba933d79..5619a58d 100644 --- a/tests/unit/vendors/test_redis.py +++ b/tests/unit/vendors/test_redis.py @@ -5,6 +5,7 @@ from pytest_celery import CELERY_REDIS_BROKER from pytest_celery import REDIS_ENV from pytest_celery import REDIS_IMAGE +from pytest_celery import REDIS_PORTS from pytest_celery import RedisContainer from pytest_celery import RedisTestBackend from pytest_celery import RedisTestBroker @@ -20,16 +21,23 @@ def test_env(self): def test_image(self): assert RedisContainer.image() == REDIS_IMAGE + def test_ports(self): + assert RedisContainer.ports() == REDIS_PORTS + @pytest.mark.parametrize("backend", [lazy_fixture(CELERY_REDIS_BACKEND)]) class test_redis_backend_api: - def test_ready(self, backend: RedisTestBackend): - backend.ready() - backend.container.ready.assert_called_once() + def test_teardown(self, backend: RedisTestBackend): + backend.teardown() + backend.container.teardown.assert_called_once() @pytest.mark.parametrize("broker", [lazy_fixture(CELERY_REDIS_BROKER)]) class test_redis_broker_api: - def test_ready(self, broker: RedisTestBroker): - broker.ready() - broker.container.ready.assert_called_once() + @pytest.mark.skip(reason="Placeholder") + def test_placeholder(self, broker: RedisTestBroker): + # The class RedisTestBroker is currently a placeholder + # so we don't have any specific tests for it yet. + # This test suite is pre-configured to test the RedisTestBroker + # and ready to be used once the class is implemented. + pass diff --git a/tests/unit/vendors/test_worker.py b/tests/unit/vendors/test_worker.py index 3a3fee0d..34263ed0 100644 --- a/tests/unit/vendors/test_worker.py +++ b/tests/unit/vendors/test_worker.py @@ -1,13 +1,10 @@ import inspect -import pytest -from celery import Celery -from pytest_lazyfixture import lazy_fixture - -from pytest_celery import CELERY_SETUP_WORKER from pytest_celery import DEFAULT_WORKER_ENV +from pytest_celery import DEFAULT_WORKER_LOG_LEVEL +from pytest_celery import DEFAULT_WORKER_NAME +from pytest_celery import DEFAULT_WORKER_QUEUE from pytest_celery import DEFAULT_WORKER_VERSION -from pytest_celery import CeleryTestWorker from pytest_celery import CeleryWorkerContainer @@ -15,12 +12,32 @@ class test_celery_worker_container: def test_version(self): assert CeleryWorkerContainer.version() == DEFAULT_WORKER_VERSION - def test_env(self, celery_worker_cluster_config: dict): - assert CeleryWorkerContainer.env(celery_worker_cluster_config) == DEFAULT_WORKER_ENV + def test_log_level(self): + assert CeleryWorkerContainer.log_level() == DEFAULT_WORKER_LOG_LEVEL + + def test_worker_name(self): + assert CeleryWorkerContainer.worker_name() == DEFAULT_WORKER_NAME + + def test_worker_queue(self): + assert CeleryWorkerContainer.worker_queue() == DEFAULT_WORKER_QUEUE def test_tasks_modules(self): assert CeleryWorkerContainer.tasks_modules() == set() + def test_signals_modules(self): + assert CeleryWorkerContainer.signals_modules() == set() + + def test_buildargs(self): + assert CeleryWorkerContainer.buildargs() == { + "CELERY_VERSION": DEFAULT_WORKER_VERSION, + "CELERY_LOG_LEVEL": DEFAULT_WORKER_LOG_LEVEL, + "CELERY_WORKER_NAME": DEFAULT_WORKER_NAME, + "CELERY_WORKER_QUEUE": DEFAULT_WORKER_QUEUE, + } + + def test_env(self, celery_worker_cluster_config: dict): + assert CeleryWorkerContainer.env(celery_worker_cluster_config) == DEFAULT_WORKER_ENV + def test_initial_content_default_tasks(self): from tests import tasks @@ -41,16 +58,3 @@ def test_initial_content_import_formatting(self): def test_task_modules(self): assert CeleryWorkerContainer.tasks_modules() == set() - - -@pytest.mark.parametrize("worker", [lazy_fixture(CELERY_SETUP_WORKER)]) -class test_base_worker_api: - def test_ready(self, worker: CeleryTestWorker): - worker.ready() - worker.container.ready.assert_called_once() - - def test_app(self, worker: CeleryTestWorker, celery_setup_app: Celery): - assert worker.app is celery_setup_app - - def test_version(self, worker: CeleryTestWorker): - assert worker.version == CeleryWorkerContainer.version()