diff --git a/src-docs/runner_manager.md b/src-docs/runner_manager.md
index 6cfdf64b5..a848bf4fb 100644
--- a/src-docs/runner_manager.md
+++ b/src-docs/runner_manager.md
@@ -3,7 +3,7 @@
# module `runner_manager`
-Runner Manager manages the runners on LXD and GitHub.
+Module for managing reactive runners.
**Global Variables**
---------------
@@ -17,6 +17,31 @@ Runner Manager manages the runners on LXD and GitHub.
- **TIMEOUT_COMMAND**
- **UBUNTU_USER**
+---
+
+
+
+## function `reconcile`
+
+```python
+reconcile(quantity: int, config: ReactiveRunnerConfig) → int
+```
+
+Spawn a runner reactively.
+
+
+
+**Args:**
+
+ - `quantity`: The number of runners to spawn.
+ - `config`: The configuration for the reactive runner.
+
+
+
+**Raises:**
+
+ - `ReactiveRunnerError`: If the runner fails to spawn.
+
---
@@ -32,7 +57,7 @@ Manage a group of runners according to configuration.
- `runner_bin_path`: The github runner app scripts path.
- `cron_path`: The path to runner build image cron job.
-
+
### method `__init__`
@@ -59,7 +84,7 @@ Construct RunnerManager object for creating and managing runners.
---
-
+
### method `build_runner_image`
@@ -79,7 +104,7 @@ Build container image in test mode, else virtual machine image.
---
-
+
### method `check_runner_bin`
@@ -96,7 +121,7 @@ Check if runner binary exists.
---
-
+
### method `flush`
@@ -125,7 +150,7 @@ Remove existing runners.
---
-
+
### method `get_github_info`
@@ -142,7 +167,7 @@ Get information on the runners from GitHub.
---
-
+
### method `get_latest_runner_bin_url`
@@ -173,7 +198,7 @@ The runner binary URL changes when a new version is available.
---
-
+
### method `has_runner_image`
@@ -190,7 +215,7 @@ Check if the runner image exists.
---
-
+
### method `reconcile`
@@ -214,7 +239,7 @@ Bring runners in line with target.
---
-
+
### method `schedule_build_runner_image`
@@ -226,7 +251,7 @@ Install cron job for building runner image.
---
-
+
### method `update_runner_bin`
@@ -253,7 +278,7 @@ Remove the existing runner binary to prevent it from being used. This is done to
---
-
+
## class `ReactiveRunnerError`
Raised when a reactive runner error occurs.
@@ -264,17 +289,17 @@ Raised when a reactive runner error occurs.
---
-
+
-## class `ReactiveRunnerManager`
-A class to manage the reactive runners.
+## class `ReactiveRunnerConfig`
+ReactiveRunnerConfig(mq_uri: str, queue_name: str)
-
+
### method `__init__`
```python
-__init__(reactive_config: ReactiveConfig, queue_name: str)
+__init__(mq_uri: str, queue_name: str) → None
```
@@ -284,28 +309,4 @@ __init__(reactive_config: ReactiveConfig, queue_name: str)
----
-
-
-
-### method `reconcile`
-
-```python
-reconcile(quantity: int) → int
-```
-
-Spawn a runner reactively.
-
-
-
-**Args:**
-
- - `queue_name`: The name of the queue.
-
-
-
-**Raises:**
-
- - `ReactiveRunnerError`: If the runner fails to spawn.
-
diff --git a/src-docs/runner_manager.py.md b/src-docs/runner_manager.py.md
index 3ad9cbedb..8cff1dd26 100644
--- a/src-docs/runner_manager.py.md
+++ b/src-docs/runner_manager.py.md
@@ -23,7 +23,7 @@ Manage a group of runners according to configuration.
- `runner_bin_path`: The github runner app scripts path.
- `cron_path`: The path to runner build image cron job.
-
+
### function `__init__`
@@ -50,7 +50,7 @@ Construct RunnerManager object for creating and managing runners.
---
-
+
### function `build_runner_image`
@@ -70,7 +70,7 @@ Build container image in test mode, else virtual machine image.
---
-
+
### function `check_runner_bin`
@@ -87,7 +87,7 @@ Check if runner binary exists.
---
-
+
### function `flush`
@@ -116,7 +116,7 @@ Remove existing runners.
---
-
+
### function `get_github_info`
@@ -133,7 +133,7 @@ Get information on the runners from GitHub.
---
-
+
### function `get_latest_runner_bin_url`
@@ -164,7 +164,7 @@ The runner binary URL changes when a new version is available.
---
-
+
### function `has_runner_image`
@@ -181,7 +181,7 @@ Check if the runner image exists.
---
-
+
### function `reconcile`
@@ -205,7 +205,7 @@ Bring runners in line with target.
---
-
+
### function `schedule_build_runner_image`
@@ -217,7 +217,7 @@ Install cron job for building runner image.
---
-
+
### function `update_runner_bin`
diff --git a/src/openstack_cloud/openstack_manager.py b/src/openstack_cloud/openstack_manager.py
index 4d88669c3..a378623de 100644
--- a/src/openstack_cloud/openstack_manager.py
+++ b/src/openstack_cloud/openstack_manager.py
@@ -38,6 +38,7 @@
from openstack.exceptions import OpenStackCloudException, SDKException
from paramiko.ssh_exception import NoValidConnectionsError
+import reactive.runner_manager as reactive_runner_manager
from charm_state import (
Arch,
CharmState,
@@ -69,7 +70,6 @@
from metrics import runner as runner_metrics
from metrics import storage as metrics_storage
from metrics.runner import RUNNER_INSTALLED_TS_FILE_NAME
-from reactive.runner_manager import ReactiveRunnerManager
from repo_policy_compliance_client import RepoPolicyComplianceClient
from runner_manager import IssuedMetricEventsStats
from runner_manager_type import OpenstackRunnerManagerConfig
@@ -587,10 +587,10 @@ def _reconcile_reactive(self, quantity: int) -> int:
quantity: Number of intended runners.
"""
logger.info("Reactive mode is experimental and not yet fully implemented.")
- reactive_runner_manager = ReactiveRunnerManager(
- reactive_config=self._config.reactive_config, queue_name=self.app_name
+ config = reactive_runner_manager.ReactiveRunnerConfig(
+ mq_uri=self._config.reactive_config.mq_uri, queue_name=self.app_name
)
- return reactive_runner_manager.reconcile(quantity=quantity)
+ return reactive_runner_manager.reconcile(quantity=quantity, config=config)
def _reconcile_runners(self, quantity: int) -> int:
"""Reconcile the number of runners.
diff --git a/src/reactive/runner_manager.py b/src/reactive/runner_manager.py
index f6b7b43b2..5cedecc2c 100644
--- a/src/reactive/runner_manager.py
+++ b/src/reactive/runner_manager.py
@@ -1,11 +1,13 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.
+
+"""Module for managing reactive runners."""
import logging
import shutil
import subprocess
+from dataclasses import dataclass
from pathlib import Path
-from charm_state import ReactiveConfig
from utilities import secure_run_subprocess
logger = logging.getLogger(__name__)
@@ -23,91 +25,97 @@ class ReactiveRunnerError(Exception):
"""Raised when a reactive runner error occurs."""
-class ReactiveRunnerManager:
- """A class to manage the reactive runners."""
-
- def __init__(self, reactive_config: ReactiveConfig, queue_name: str):
- self._reactive_config = reactive_config
- self._queue_name = queue_name
-
- def reconcile(self, quantity: int) -> int:
- """Spawn a runner reactively.
-
- Args:
- queue_name: The name of the queue.
-
- Raises:
- ReactiveRunnerError: If the runner fails to spawn.
- """
-
- actual_quantity = self._determine_current_quantity()
- logger.info("Actual quantity of ReactiveRunner processes: %s", actual_quantity)
- delta = quantity - actual_quantity
- actual_delta = delta
- if delta > 0:
- logger.info("Will spawn %d new ReactiveRunner processes", delta)
- self._setup_log_file()
- for _ in range(delta):
- try:
- self._spawn_runner()
- except ReactiveRunnerError:
- logger.exception("Failed to spawn a new ReactiveRunner process")
- actual_delta -= 1
- elif delta < 0:
- logger.info(
- "%d ReactiveRunner processes are running. Will skip spawning. Additional processes should terminate after %s.",
- actual_quantity,
- REACTIVE_RUNNER_TIMEOUT_STR,
- )
- else:
- logger.info("No changes to number of ReactiveRunners needed.")
-
- return max(actual_delta, 0)
-
- def _determine_current_quantity(self):
- """Determine the current quantity of reactive runners.
-
- Returns:
- The number of reactive runners.
-
- Raises:
- ReactiveRunnerError: If the number of reactive runners cannot be determined
- """
- result = secure_run_subprocess(cmd=PS_COMMAND_LINE_LIST)
- if result.returncode != 0:
- raise ReactiveRunnerError("Failed to get list of processes")
- commands = result.stdout.decode().rstrip().split("\n")[1:]
- logger.debug(commands)
- actual_quantity = 0
- for command in commands:
- if command.startswith(f"{PYTHON_BIN} {REACTIVE_RUNNER_SCRIPT_FILE}"):
- actual_quantity += 1
- return actual_quantity
-
- def _setup_log_file(self) -> None:
- """Set up the log file."""
- logfile = Path(REACTIVE_RUNNER_LOG_FILE)
- if not logfile.exists():
- logfile.touch()
- shutil.chown(logfile, user=UBUNTU_USER, group=UBUNTU_USER)
-
- def _spawn_runner(self) -> None:
- """Spawn a runner."""
- env = {"PYTHONPATH": "src:lib:venv"}
- process = subprocess.Popen(
- [
- TIMEOUT_COMMAND,
- REACTIVE_RUNNER_TIMEOUT_STR,
- PYTHON_BIN,
- REACTIVE_RUNNER_SCRIPT_FILE,
- self._reactive_config.mq_uri,
- self._queue_name,
- ],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- env=env,
- user=UBUNTU_USER,
+@dataclass
+class ReactiveRunnerConfig:
+
+ mq_uri: str
+ queue_name: str
+
+
+def reconcile(quantity: int, config: ReactiveRunnerConfig) -> int:
+ """Spawn a runner reactively.
+
+ Args:
+ quantity: The number of runners to spawn.
+ config: The configuration for the reactive runner.
+
+ Raises:
+ ReactiveRunnerError: If the runner fails to spawn.
+ """
+
+ actual_quantity = _determine_current_quantity()
+ logger.info("Actual quantity of reactive runner processes: %s", actual_quantity)
+ delta = quantity - actual_quantity
+ actual_delta = delta
+ if delta > 0:
+ logger.info("Will spawn %d new reactive runner processes", delta)
+ _setup_log_file()
+ for _ in range(delta):
+ try:
+ _spawn_runner(config)
+ except ReactiveRunnerError:
+ logger.exception("Failed to spawn a new reactive runner process")
+ actual_delta -= 1
+ elif delta < 0:
+ logger.info(
+ "%d reactive runner processes are running. Will skip spawning. Additional processes should terminate after %s.",
+ actual_quantity,
+ REACTIVE_RUNNER_TIMEOUT_STR,
+ )
+ else:
+ logger.info("No changes to number of reactive runner processes needed.")
+
+ return max(actual_delta, 0)
+
+
+def _determine_current_quantity():
+ """Determine the current quantity of reactive runners.
+
+ Returns:
+ The number of reactive runners.
+
+ Raises:
+ ReactiveRunnerError: If the number of reactive runners cannot be determined
+ """
+ result = secure_run_subprocess(cmd=PS_COMMAND_LINE_LIST)
+ if result.returncode != 0:
+ raise ReactiveRunnerError("Failed to get list of processes")
+ commands = result.stdout.decode().rstrip().split("\n")[1:]
+ logger.debug(commands)
+ actual_quantity = 0
+ for command in commands:
+ if command.startswith(f"{PYTHON_BIN} {REACTIVE_RUNNER_SCRIPT_FILE}"):
+ actual_quantity += 1
+ return actual_quantity
+
+
+def _setup_log_file() -> None:
+ """Set up the log file."""
+ logfile = Path(REACTIVE_RUNNER_LOG_FILE)
+ if not logfile.exists():
+ logfile.touch()
+ shutil.chown(logfile, user=UBUNTU_USER, group=UBUNTU_USER)
+
+
+def _spawn_runner(reactive_runner_config: ReactiveRunnerConfig) -> None:
+ """Spawn a runner."""
+ env = {"PYTHONPATH": "src:lib:venv"}
+ process = subprocess.Popen(
+ [
+ TIMEOUT_COMMAND,
+ REACTIVE_RUNNER_TIMEOUT_STR,
+ PYTHON_BIN,
+ REACTIVE_RUNNER_SCRIPT_FILE,
+ reactive_runner_config.mq_uri,
+ reactive_runner_config.queue_name,
+ ],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ env=env,
+ user=UBUNTU_USER,
+ )
+ logger.debug("Spawned a new reactive runner process with pid %s", process.pid)
+ if process.returncode not in (0, None):
+ raise ReactiveRunnerError(
+ "Failed to spawn a new reactive runner process. Return code: %s" % process.returncode
)
- logger.debug("Spawned a new ReactiveRunner process with pid %s", process.pid)
- if process.returncode not in (0, None):
- raise ReactiveRunnerError("Failed to spawn a new ReactiveRunner process")
diff --git a/src/runner_manager.py b/src/runner_manager.py
index c94b1be23..5cb7ec0b1 100644
--- a/src/runner_manager.py
+++ b/src/runner_manager.py
@@ -9,9 +9,7 @@
import secrets
import tarfile
import time
-from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
-from multiprocessing import Pool
from pathlib import Path
from typing import Iterator, Optional, Type
@@ -20,8 +18,9 @@
import requests.adapters
import urllib3
+import reactive.runner_manager as reactive_runner_manager
import shared_fs
-from charm_state import ReactiveConfig, VirtualMachineResources
+from charm_state import VirtualMachineResources
from errors import (
GetMetricsStorageError,
GithubClientError,
@@ -40,7 +39,6 @@
from metrics import runner as runner_metrics
from metrics import runner_logs
from metrics.runner import RUNNER_INSTALLED_TS_FILE_NAME
-from reactive.runner_manager import ReactiveRunnerManager
from repo_policy_compliance_client import RepoPolicyComplianceClient
from runner import LXD_PROFILE_YAML, CreateRunnerConfig, Runner, RunnerConfig, RunnerStatus
from runner_manager_type import FlushMode, RunnerInfo, RunnerManagerClients, RunnerManagerConfig
@@ -583,10 +581,10 @@ def _reconcile_reactive(self, quantity: int) -> int:
quantity: Number of intended runners.
"""
logger.info("Reactive mode is experimental and not yet fully implemented.")
- reactive_runner_manager = ReactiveRunnerManager(
- reactive_config=self.config.reactive_config, queue_name=self.app_name
+ config = reactive_runner_manager.ReactiveRunnerConfig(
+ mq_uri=self.config.reactive_config.mq_uri, queue_name=self.app_name
)
- return reactive_runner_manager.reconcile(quantity=quantity)
+ return reactive_runner_manager.reconcile(quantity=quantity, config=config)
def _runners_in_pre_job(self) -> bool:
"""Check there exist runners in the pre-job script stage.
diff --git a/tests/unit/reactive/test_runner_manager.py b/tests/unit/reactive/test_runner_manager.py
index 3ffc7ef90..4a410ade8 100644
--- a/tests/unit/reactive/test_runner_manager.py
+++ b/tests/unit/reactive/test_runner_manager.py
@@ -1,6 +1,7 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.
import random
+import secrets
import subprocess
from pathlib import Path
from subprocess import CompletedProcess
@@ -13,11 +14,12 @@
PS_COMMAND_LINE_LIST,
PYTHON_BIN,
REACTIVE_RUNNER_SCRIPT_FILE,
- ReactiveRunnerError,
- ReactiveRunnerManager,
+ ReactiveRunnerError, ReactiveRunnerConfig,
+reconcile
)
from utilities import secure_run_subprocess
+EXAMPLE_MQ_URI = "http://example.com"
@pytest.fixture(name="log_file_path", autouse=True)
def log_file_path_fixture(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
@@ -57,11 +59,11 @@ def test_reconcile_spawns_runners(
act: Call reconcile with a quantity of 5.
assert: Three runners are spawned. Log file is setup.
"""
- reactive_config = ReactiveConfig(mq_uri="http://example.com")
+ queue_name = secrets.token_hex(16)
+ reactive_config = ReactiveRunnerConfig(mq_uri=EXAMPLE_MQ_URI, queue_name=queue_name)
_arrange_reactive_processes(secure_run_subprocess_mock, count=2)
- manager = ReactiveRunnerManager(reactive_config, "test-queue")
- delta = manager.reconcile(5)
+ delta = reconcile(5, reactive_config)
assert delta == 3
assert subprocess_popen_mock.call_count == 3
@@ -92,11 +94,11 @@ def test_reconcile_does_not_spawn_runners(
act: Call reconcile with a quantity of 2.
assert: No runners are spawned.
"""
- reactive_config = ReactiveConfig(mq_uri="http://example.com")
+ queue_name = secrets.token_hex(16)
+ reactive_config = ReactiveRunnerConfig(mq_uri=EXAMPLE_MQ_URI, queue_name=queue_name)
_arrange_reactive_processes(secure_run_subprocess_mock, count=2)
- manager = ReactiveRunnerManager(reactive_config, "test-queue")
- delta = manager.reconcile(2)
+ delta = reconcile(2, reactive_config)
assert delta == 0
assert subprocess_popen_mock.call_count == 0
@@ -110,10 +112,10 @@ def test_reconcile_does_not_spawn_runners_for_too_many_processes(
act: Call reconcile with a quantity of 1.
assert: No runners are spawned and delta is 0.
"""
- reactive_config = ReactiveConfig(mq_uri="http://example.com")
+ queue_name = secrets.token_hex(16)
+ reactive_config = ReactiveRunnerConfig(mq_uri=EXAMPLE_MQ_URI, queue_name=queue_name)
_arrange_reactive_processes(secure_run_subprocess_mock, count=2)
- manager = ReactiveRunnerManager(reactive_config, "test-queue")
- delta = manager.reconcile(1)
+ delta = reconcile(1, reactive_config)
assert delta == 0
assert subprocess_popen_mock.call_count == 0
@@ -127,6 +129,8 @@ def test_reconcile_raises_reactive_runner_error_on_ps_failure(
act: Call reconcile with a quantity of 1.
assert: A ReactiveRunnerError is raised.
"""
+ queue_name = secrets.token_hex(16)
+ reactive_config = ReactiveRunnerConfig(mq_uri=EXAMPLE_MQ_URI, queue_name=queue_name)
secure_run_subprocess_mock.return_value = CompletedProcess(
args=PS_COMMAND_LINE_LIST,
returncode=1,
@@ -134,10 +138,9 @@ def test_reconcile_raises_reactive_runner_error_on_ps_failure(
stderr=b"error",
)
- reactive_config = ReactiveConfig(mq_uri="http://example.com")
- manager = ReactiveRunnerManager(reactive_config, "test-queue")
+ reactive_config = ReactiveConfig(mq_uri=EXAMPLE_MQ_URI)
with pytest.raises(ReactiveRunnerError) as err:
- manager.reconcile(1)
+ reconcile(1, reactive_config)
assert "Failed to get list of processes" in str(err.value)
@@ -150,6 +153,8 @@ def test_reconcile_spawn_runner_failed(
act: Call reconcile with a quantity of 3.
assert: The delta is 2.
"""
+ queue_name = secrets.token_hex(16)
+ reactive_config = ReactiveRunnerConfig(mq_uri=EXAMPLE_MQ_URI, queue_name=queue_name)
subprocess_popen_mock.side_effect = [
MagicMock(returncode=0),
MagicMock(return_code=1),
@@ -157,8 +162,6 @@ def test_reconcile_spawn_runner_failed(
]
_arrange_reactive_processes(secure_run_subprocess_mock, count=0)
- reactive_config = ReactiveConfig(mq_uri="http://example.com")
- manager = ReactiveRunnerManager(reactive_config, "test-queue")
- delta = manager.reconcile(3)
+ delta = reconcile(3, reactive_config)
assert delta == 2
diff --git a/tests/unit/test_openstack_manager.py b/tests/unit/test_openstack_manager.py
index 6e3ab57d8..123d60150 100644
--- a/tests/unit/test_openstack_manager.py
+++ b/tests/unit/test_openstack_manager.py
@@ -17,6 +17,7 @@
from pytest import LogCaptureFixture, MonkeyPatch
import metrics.storage
+import reactive.runner_manager
from charm_state import CharmState, ProxyConfig, ReactiveConfig, RepoPolicyComplianceConfig
from errors import OpenStackError, RunnerStartError
from github_type import GitHubRunnerStatus, SelfHostedRunner
@@ -25,7 +26,6 @@
from metrics.storage import MetricsStorage
from openstack_cloud import openstack_manager
from openstack_cloud.openstack_manager import MAX_METRICS_FILE_SIZE, METRICS_EXCHANGE_PATH
-from reactive.runner_manager import ReactiveRunnerManager
from runner_type import RunnerByHealth, RunnerGithubInfo
from tests.unit import factories
@@ -248,14 +248,15 @@ def pool_map(func, iterable):
return os_runner_manager
-@pytest.fixture(name="reactive_runner_manager_mock")
-def reactive_runner_manager_fixture(monkeypatch: MonkeyPatch, tmp_path: Path) -> MagicMock:
+@pytest.fixture(name="reactive_reconcile_mock")
+def reactive_reconcile_fixture(monkeypatch: MonkeyPatch, tmp_path: Path) -> MagicMock:
"""Mock the job class."""
- reactive_runner_manager = MagicMock(spec=ReactiveRunnerManager)
- monkeypatch.setattr("openstack_cloud.openstack_manager.ReactiveRunnerManager", MagicMock(return_value=reactive_runner_manager))
- reactive_runner_manager.reconcile.side_effect = lambda quantity: quantity
- return reactive_runner_manager
-
+ reconcile_mock = MagicMock(spec=reactive.runner_manager.reconcile)
+ monkeypatch.setattr(
+ "openstack_cloud.openstack_manager.reactive_runner_manager.reconcile", reconcile_mock
+ )
+ reconcile_mock.side_effect = lambda quantity, **kwargs: quantity
+ return reconcile_mock
def test__create_connection_error(clouds_yaml: dict, openstack_connect_mock: MagicMock):
@@ -1017,7 +1018,9 @@ def test_reconcile_ignores_metrics_for_openstack_online_runners(
def test_reconcile_reactive_mode(
- openstack_manager_for_reconcile: openstack_manager.OpenstackRunnerManager, reactive_runner_manager_mock: MagicMock, caplog: LogCaptureFixture
+ openstack_manager_for_reconcile: openstack_manager.OpenstackRunnerManager,
+ reactive_reconcile_mock: MagicMock,
+ caplog: LogCaptureFixture,
):
"""
arrange: Enable reactive mode and mock the job class to return a job.
@@ -1031,7 +1034,12 @@ def test_reconcile_reactive_mode(
actual_count = openstack_manager_for_reconcile.reconcile(quantity=count)
assert actual_count == count
- reactive_runner_manager_mock.reconcile.assert_called_with(quantity=count)
+ reactive_reconcile_mock.assert_called_with(
+ quantity=count,
+ config=reactive.runner_manager.ReactiveRunnerConfig(
+ mq_uri="http://example.com", queue_name=openstack_manager_for_reconcile.app_name
+ ),
+ )
def test_repo_policy_config(
diff --git a/tests/unit/test_runner_manager.py b/tests/unit/test_runner_manager.py
index 88c840b8e..b173ec485 100644
--- a/tests/unit/test_runner_manager.py
+++ b/tests/unit/test_runner_manager.py
@@ -10,6 +10,7 @@
import pytest
from pytest import LogCaptureFixture, MonkeyPatch
+import reactive.runner_manager
import shared_fs
from charm_state import (
Arch,
@@ -26,7 +27,6 @@
from metrics.events import Reconciliation, RunnerInstalled, RunnerStart, RunnerStop
from metrics.runner import RUNNER_INSTALLED_TS_FILE_NAME
from metrics.storage import MetricsStorage
-from reactive.runner_manager import ReactiveRunnerManager
from runner import Runner, RunnerStatus
from runner_manager import BUILD_IMAGE_SCRIPT_FILENAME, RunnerManager, RunnerManagerConfig
from runner_type import RunnerByHealth
@@ -126,13 +126,13 @@ def runner_metrics_fixture(monkeypatch: MonkeyPatch) -> MagicMock:
return runner_metrics_mock
-@pytest.fixture(name="reactive_runner_manager_mock")
-def reactive_runner_manager_fixture(monkeypatch: MonkeyPatch, tmp_path: Path) -> MagicMock:
+@pytest.fixture(name="reactive_reconcile_mock")
+def reactive_reconcile_fixture(monkeypatch: MonkeyPatch, tmp_path: Path) -> MagicMock:
"""Mock the job class."""
- reactive_runner_manager = MagicMock(spec=ReactiveRunnerManager)
- monkeypatch.setattr("runner_manager.ReactiveRunnerManager", MagicMock(return_value=reactive_runner_manager))
- reactive_runner_manager.reconcile.side_effect = lambda quantity: quantity
- return reactive_runner_manager
+ reconcile_mock = MagicMock(spec=reactive.runner_manager.reconcile)
+ monkeypatch.setattr("runner_manager.reactive_runner_manager.reconcile", reconcile_mock)
+ reconcile_mock.side_effect = lambda quantity, **kwargs: quantity
+ return reconcile_mock
@pytest.mark.parametrize(
@@ -520,7 +520,9 @@ def test_reconcile_places_no_timestamp_in_newly_created_runner_if_metrics_disabl
def test_reconcile_reactive_mode(
- runner_manager: RunnerManager, reactive_runner_manager_mock: MagicMock, caplog: LogCaptureFixture
+ runner_manager: RunnerManager,
+ reactive_reconcile_mock: MagicMock,
+ caplog: LogCaptureFixture,
):
"""
arrange: Enable reactive mode and mock the job class to return a job.
@@ -532,7 +534,12 @@ def test_reconcile_reactive_mode(
actual_count = runner_manager.reconcile(count, VirtualMachineResources(2, "7GiB", "10Gib"))
assert actual_count == count
- reactive_runner_manager_mock.reconcile.assert_called_with(quantity=count)
+ reactive_reconcile_mock.assert_called_with(
+ quantity=count,
+ config=reactive.runner_manager.ReactiveRunnerConfig(
+ mq_uri="http://example.com", queue_name=runner_manager.app_name
+ ),
+ )
def test_schedule_build_runner_image(