Просмотр исходного кода

tests: add/update tests for provider based versions manager

Shiv Tyagi 2 месяцев назад
Родитель
Сommit
0cbe1e1ec6

+ 62 - 0
tests/metadata_manager/fixtures/manifest_sample.json

@@ -0,0 +1,62 @@
+{
+  "format-version": "1.0.0",
+  "firmware": [
+    {
+      "vehicletype": "Copter",
+      "platform": "CubeOrange",
+      "git-sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+      "url": "https://firmware.ardupilot.org/Copter/stable-4.6.3/CubeOrange/arducopter.apj",
+      "mav-firmware-version-type": "STABLE-4.6.3",
+      "mav-firmware-version": "4.6.3",
+      "format": "apj",
+      "latest": 0,
+      "mav-type": "QUADROTOR",
+      "image_size": 100
+    },
+    {
+      "vehicletype": "Copter",
+      "platform": "CubeOrange-heli",
+      "git-sha": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      "url": "https://firmware.ardupilot.org/Copter/stable-4.6.3/CubeOrange-heli/arducopter-heli.apj",
+      "mav-firmware-version-type": "STABLE-4.6.3",
+      "mav-firmware-version": "4.6.3",
+      "format": "apj",
+      "latest": 0,
+      "mav-type": "HELICOPTER",
+      "image_size": 100
+    },
+    {
+      "vehicletype": "Copter",
+      "platform": "CubeOrange",
+      "git-sha": "cccccccccccccccccccccccccccccccccccccccc",
+      "url": "https://firmware.ardupilot.org/Copter/beta/CubeOrange/arducopter.apj",
+      "mav-firmware-version-type": "BETA",
+      "mav-firmware-version": "4.7.0",
+      "format": "apj",
+      "latest": 0,
+      "mav-type": "QUADROTOR"
+    },
+    {
+      "vehicletype": "AntennaTracker",
+      "platform": "CubeOrange",
+      "git-sha": "dddddddddddddddddddddddddddddddddddddddd",
+      "url": "https://firmware.ardupilot.org/AntennaTracker/stable-4.6.3/CubeOrange/antennatracker.apj",
+      "mav-firmware-version-type": "STABLE-4.6.3",
+      "mav-firmware-version": "4.6.3",
+      "format": "apj",
+      "latest": 0,
+      "mav-type": "ANTENNA_TRACKER"
+    },
+    {
+      "vehicletype": "Copter",
+      "platform": "CubeOrange",
+      "git-sha": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+      "url": "https://firmware.ardupilot.org/Copter/latest/CubeOrange/arducopter.apj",
+      "mav-firmware-version-type": "DEV",
+      "mav-firmware-version": "4.8.0",
+      "format": "apj",
+      "latest": 1,
+      "mav-type": "QUADROTOR"
+    }
+  ]
+}

+ 54 - 0
tests/metadata_manager/test_firmware_server.py

@@ -0,0 +1,54 @@
+import json
+from pathlib import Path
+from unittest.mock import Mock, patch
+
+from metadata_manager import ManifestClient, ManifestIndex
+from metadata_manager.firmware_server.client import _CacheMeta
+
+
+FIXTURES_DIR = Path(__file__).parent / "fixtures"
+SAMPLE_MANIFEST = json.loads((FIXTURES_DIR / "manifest_sample.json").read_text())
+
+
+class TestManifestIndex:
+    def test_builds_releases_for_copter_heli_and_tracker(self):
+        index = ManifestIndex.build(SAMPLE_MANIFEST)
+
+        copter = index.get_releases("copter")
+        stable = [r for r in copter if r.release_type == "stable" and r.version_number == "4.6.3"]
+        assert len(stable) == 1
+        assert stable[0].commit_reference.startswith("aaaa")
+
+        heli = index.get_releases("heli")
+        heli_stable = [r for r in heli if r.release_type == "stable" and r.version_number == "4.6.3"]
+        assert len(heli_stable) == 1
+        assert heli_stable[0].commit_reference.startswith("bbbb")
+
+        tracker = index.get_releases("tracker")
+        assert any(r.version_number == "4.6.3" for r in tracker)
+
+        latest = [r for r in copter if r.release_type == "latest"]
+        assert len(latest) == 1
+        assert latest[0].commit_reference.startswith("eeee")
+        assert latest[0].version_number == "NA"
+        assert latest[0].ap_build_artifacts_url == (
+            "https://firmware.ardupilot.org/Copter/latest"
+        )
+
+
+class TestManifestClientCache:
+    def test_uses_cache_on_304(self, tmp_path):
+        client = ManifestClient(
+            url="https://example.com/manifest.json",
+            cache_dir=str(tmp_path),
+        )
+        client._write_cache(
+            b'{"format-version":"1.0.0","firmware":[]}',
+            _CacheMeta(etag='"abc"', last_modified="Mon, 01 Jan 2024 00:00:00 GMT"),
+        )
+
+        response = Mock(status_code=304, headers={}, content=b"")
+        with patch("metadata_manager.firmware_server.client.requests.get", return_value=response):
+            raw = client.fetch_raw()
+
+        assert raw == b'{"format-version":"1.0.0","firmware":[]}'

+ 123 - 0
tests/metadata_manager/test_versions_manager.py

@@ -0,0 +1,123 @@
+from unittest.mock import Mock, PropertyMock
+
+import pytest
+
+from metadata_manager import (
+    DEFAULT_WHITELISTED_FORK_REMOTES,
+    ForkRemoteSpec,
+    ManifestJSON,
+    ManifestJsonVersionsProvider,
+    RemoteInfo,
+    VehiclesManager,
+    VersionInfo,
+    VersionsManager,
+)
+
+
+@pytest.fixture
+def vehicles_manager():
+    existing = VehiclesManager.get_singleton()
+    if existing is not None:
+        return existing
+    return VehiclesManager()
+
+
+@pytest.fixture
+def versions_manager(vehicles_manager, tmp_path):
+    VersionsManager._VersionsManager__singleton = None
+    repo = Mock()
+    manager = VersionsManager(
+        ap_repo=repo,
+        remotes_json_path=str(tmp_path / "missing-remotes.json"),
+        providers=[],
+    )
+    yield manager
+    VersionsManager._VersionsManager__singleton = None
+
+
+class TestManifestJsonVersionsProvider:
+    def test_is_available_when_manifest_is_available(self, vehicles_manager):
+        manifest_json = Mock(spec=ManifestJSON)
+        type(manifest_json).is_available = PropertyMock(return_value=True)
+
+        provider = ManifestJsonVersionsProvider(manifest_json)
+
+        assert provider.is_available is True
+
+    def test_is_unavailable_when_manifest_is_unavailable(self, vehicles_manager):
+        manifest_json = Mock(spec=ManifestJSON)
+        type(manifest_json).is_available = PropertyMock(return_value=False)
+
+        provider = ManifestJsonVersionsProvider(manifest_json)
+
+        assert provider.is_available is False
+        assert provider.get_versions("copter") == []
+        assert provider.get_remotes() == []
+
+    def test_refresh_delegates_to_manifest_json(self, vehicles_manager):
+        manifest_json = Mock(spec=ManifestJSON)
+        provider = ManifestJsonVersionsProvider(manifest_json)
+
+        provider.refresh()
+
+        manifest_json.refresh.assert_called_once()
+
+
+class TestVersionsManagerDedup:
+    def _make_version(self, release_type: str, version_number: str, commit_ref: str):
+        remote = RemoteInfo("ardupilot", "https://github.com/ardupilot/ardupilot.git")
+        return VersionInfo(
+            remote_info=remote,
+            commit_ref=commit_ref,
+            release_type=release_type,
+            version_number=version_number,
+            ap_build_artifacts_url=None,
+        )
+
+    def test_stable_wins_when_beta_is_seen_first(self, versions_manager):
+        commit = "03c12698df56c600f5b3d39f8b17d414ea6d2a48"
+        beta = self._make_version("beta", "4.5.0", commit)
+        stable = self._make_version("stable", "4.5.0", commit)
+
+        beta_provider = Mock()
+        beta_provider.get_versions.return_value = [beta]
+        stable_provider = Mock()
+        stable_provider.get_versions.return_value = [stable]
+        versions_manager._providers = [beta_provider, stable_provider]
+
+        versions = versions_manager.get_versions_for_vehicle("sub")
+
+        assert len(versions) == 1
+        assert versions[0].release_type == "stable"
+        assert versions[0].version_number == "4.5.0"
+
+    def test_stable_wins_when_stable_is_seen_first(self, versions_manager):
+        commit = "03c12698df56c600f5b3d39f8b17d414ea6d2a48"
+        beta = self._make_version("beta", "4.5.0", commit)
+        stable = self._make_version("stable", "4.5.0", commit)
+
+        stable_provider = Mock()
+        stable_provider.get_versions.return_value = [stable]
+        beta_provider = Mock()
+        beta_provider.get_versions.return_value = [beta]
+        versions_manager._providers = [stable_provider, beta_provider]
+
+        versions = versions_manager.get_versions_for_vehicle("sub")
+
+        assert len(versions) == 1
+        assert versions[0].release_type == "stable"
+
+
+class TestForkRemoteSpec:
+    def test_default_rmackay9_uses_custom_repo_name(self):
+        rmackay9 = next(
+            spec for spec in DEFAULT_WHITELISTED_FORK_REMOTES if spec.owner == "rmackay9"
+        )
+        assert rmackay9.repo == "rmackay9-ardupilot"
+        assert rmackay9.github_repo == "rmackay9/rmackay9-ardupilot"
+        assert rmackay9.url == "https://github.com/rmackay9/rmackay9-ardupilot.git"
+
+    def test_fork_remote_spec_url(self):
+        spec = ForkRemoteSpec(owner="example", repo="my-ardupilot-fork")
+        assert spec.github_repo == "example/my-ardupilot-fork"
+        assert spec.url == "https://github.com/example/my-ardupilot-fork.git"

+ 21 - 22
tests/web/conftest.py

@@ -25,7 +25,7 @@ TEST_REMOTES_JSON = [
         "url": "https://github.com/test/ardupilot.git",
         "url": "https://github.com/test/ardupilot.git",
         "vehicles": [
         "vehicles": [
             {
             {
-                "name": "Copter",
+                "id": "copter",
                 "releases": [
                 "releases": [
                     {
                     {
                         "release_type": "latest",
                         "release_type": "latest",
@@ -40,7 +40,7 @@ TEST_REMOTES_JSON = [
                 ]
                 ]
             },
             },
             {
             {
-                "name": "Plane",
+                "id": "plane",
                 "releases": [
                 "releases": [
                     {
                     {
                         "release_type": "latest",
                         "release_type": "latest",
@@ -56,7 +56,7 @@ TEST_REMOTES_JSON = [
         "url": "https://github.com/another/ardupilot.git",
         "url": "https://github.com/another/ardupilot.git",
         "vehicles": [
         "vehicles": [
             {
             {
-                "name": "Rover",
+                "id": "rover",
                 "releases": [
                 "releases": [
                     {
                     {
                         "release_type": "Custom",
                         "release_type": "Custom",
@@ -90,10 +90,10 @@ def test_base_dir() -> Generator[str, None, None]:
     with open(remotes_json_path, "w") as f:
     with open(remotes_json_path, "w") as f:
         json.dump(TEST_REMOTES_JSON, f, indent=2)
         json.dump(TEST_REMOTES_JSON, f, indent=2)
 
 
-    # Create remote reload token file
-    token_file_path = os.path.join(temp_dir, "secrets", "reload_token")
+    # Create admin token file
+    token_file_path = os.path.join(temp_dir, "secrets", "admin_token")
     with open(token_file_path, "w") as f:
     with open(token_file_path, "w") as f:
-        f.write("test-remote-reload-token-12345")
+        f.write("test-admin-token-12345")
 
 
     yield temp_dir
     yield temp_dir
 
 
@@ -130,9 +130,9 @@ def mock_ap_src_metadata_fetcher():
 
 
 
 
 @pytest.fixture
 @pytest.fixture
-def mock_versions_fetcher(test_base_dir):
+def mock_versions_manager(test_base_dir):
     """
     """
-    Create a mock VersionsFetcher that doesn't actually fetch versions.
+    Create a mock VersionsManager that doesn't actually fetch versions.
 
 
     This allows tests to run without starting background threads or
     This allows tests to run without starting background threads or
     making actual git operations.
     making actual git operations.
@@ -141,27 +141,27 @@ def mock_versions_fetcher(test_base_dir):
         test_base_dir: Test base directory fixture
         test_base_dir: Test base directory fixture
 
 
     Returns:
     Returns:
-        Mock: Mock VersionsFetcher instance
+        Mock: Mock VersionsManager instance
     """
     """
-    from metadata_manager.versions_fetcher import RemoteInfo
+    from metadata_manager import RemoteInfo
 
 
-    mock_fetcher = Mock()
+    mock_manager = Mock()
 
 
-    # Mock the reload_remotes_json method
-    mock_fetcher.reload_remotes_json = Mock(return_value=None)
+    # Mock the refresh methods
+    mock_manager.refresh_all = Mock(return_value=None)
 
 
     # Mock get_all_remotes_info to return test remotes
     # Mock get_all_remotes_info to return test remotes
     test_remotes = [
     test_remotes = [
         RemoteInfo(name="test-remote-1", url="https://github.com/test/ardupilot.git"),
         RemoteInfo(name="test-remote-1", url="https://github.com/test/ardupilot.git"),
         RemoteInfo(name="test-remote-2", url="https://github.com/another/ardupilot.git")
         RemoteInfo(name="test-remote-2", url="https://github.com/another/ardupilot.git")
     ]
     ]
-    mock_fetcher.get_all_remotes_info = Mock(return_value=test_remotes)
+    mock_manager.get_all_remotes_info = Mock(return_value=test_remotes)
 
 
     # Mock start/stop methods (no-op for tests)
     # Mock start/stop methods (no-op for tests)
-    mock_fetcher.start = Mock()
-    mock_fetcher.stop = Mock()
+    mock_manager.start = Mock()
+    mock_manager.stop = Mock()
 
 
-    return mock_fetcher
+    return mock_manager
 
 
 
 
 @pytest.fixture
 @pytest.fixture
@@ -191,7 +191,6 @@ def mock_vehicles_manager():
         Mock: Mock VehiclesManager instance
         Mock: Mock VehiclesManager instance
     """
     """
     mock_manager = Mock()
     mock_manager = Mock()
-    mock_manager.get_vehicle_names = Mock(return_value=["Copter", "Plane", "Rover"])
     return mock_manager
     return mock_manager
 
 
 
 
@@ -199,7 +198,7 @@ def mock_vehicles_manager():
 def app_with_mocked_dependencies(
 def app_with_mocked_dependencies(
     test_base_dir,
     test_base_dir,
     mock_git_repo,
     mock_git_repo,
-    mock_versions_fetcher,
+    mock_versions_manager,
     mock_build_manager,
     mock_build_manager,
     mock_vehicles_manager,
     mock_vehicles_manager,
 ):
 ):
@@ -215,7 +214,7 @@ def app_with_mocked_dependencies(
     Args:
     Args:
         test_base_dir: Test base directory
         test_base_dir: Test base directory
         mock_git_repo: Mock git repository
         mock_git_repo: Mock git repository
-        mock_versions_fetcher: Mock versions fetcher
+        mock_versions_manager: Mock versions manager
         mock_build_manager: Mock build manager
         mock_build_manager: Mock build manager
         mock_vehicles_manager: Mock vehicles manager
         mock_vehicles_manager: Mock vehicles manager
 
 
@@ -240,7 +239,7 @@ def app_with_mocked_dependencies(
         """Test lifespan that doesn't start background tasks."""
         """Test lifespan that doesn't start background tasks."""
         # Setup: Attach mocked dependencies to app state
         # Setup: Attach mocked dependencies to app state
         app.state.repo = mock_git_repo
         app.state.repo = mock_git_repo
-        app.state.versions_fetcher = mock_versions_fetcher
+        app.state.versions_manager = mock_versions_manager
         app.state.vehicles_manager = mock_vehicles_manager
         app.state.vehicles_manager = mock_vehicles_manager
         app.state.build_manager = mock_build_manager
         app.state.build_manager = mock_build_manager
         app.state.limiter = limiter
         app.state.limiter = limiter
@@ -250,7 +249,7 @@ def app_with_mocked_dependencies(
         app.state.ap_src_metadata_fetcher = mock_ap_src_fetcher
         app.state.ap_src_metadata_fetcher = mock_ap_src_fetcher
 
 
         # Don't start background tasks in test mode
         # Don't start background tasks in test mode
-        # versions_fetcher.start()
+        # versions_manager.start()
         # cleaner.start()
         # cleaner.start()
         # progress_updater.start()
         # progress_updater.start()
 
 

+ 24 - 24
tests/web/test_admin_api.py

@@ -9,11 +9,11 @@ from fastapi import status
 from web.core.config import get_settings
 from web.core.config import get_settings
 
 
 
 
-class TestAdminRefreshRemotesEndpoint:
-    """Test suite for the /admin/refresh_remotes endpoint."""
+class TestAdminRefreshVersionsEndpoint:
+    """Test suite for the /admin/refresh_versions endpoint."""
 
 
-    AUTH_HEADERS = {"Authorization": "Bearer test-remote-reload-token-12345"}
-    TEST_TOKEN = "test-remote-reload-token-12345"
+    AUTH_HEADERS = {"Authorization": "Bearer test-admin-token-12345"}
+    TEST_TOKEN = "test-admin-token-12345"
 
 
     @staticmethod
     @staticmethod
     @contextmanager
     @contextmanager
@@ -25,8 +25,8 @@ class TestAdminRefreshRemotesEndpoint:
         finally:
         finally:
             client.app.dependency_overrides.pop(get_settings, None)
             client.app.dependency_overrides.pop(get_settings, None)
 
 
-    def test_refresh_remotes_success(self, client, test_base_dir):
-        """Test successful refresh of remotes with valid auth and verifies against remotes.json."""
+    def test_refresh_versions_success(self, client, test_base_dir):
+        """Test successful refresh with valid auth and verifies against remotes.json."""
         import os
         import os
         import json
         import json
 
 
@@ -37,10 +37,10 @@ class TestAdminRefreshRemotesEndpoint:
             initial_remotes = json.load(f)
             initial_remotes = json.load(f)
 
 
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
             response = client.post(
             response = client.post(
-                "/api/v1/admin/refresh_remotes",
+                "/api/v1/admin/refresh_versions",
                 headers=self.AUTH_HEADERS
                 headers=self.AUTH_HEADERS
             )
             )
 
 
@@ -54,22 +54,22 @@ class TestAdminRefreshRemotesEndpoint:
         for name in expected_names:
         for name in expected_names:
             assert name in data["remotes"]
             assert name in data["remotes"]
 
 
-    def test_refresh_remotes_no_auth(self, client):
+    def test_refresh_versions_no_auth(self, client):
         """Test refresh without authentication - should fail."""
         """Test refresh without authentication - should fail."""
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
-            response = client.post("/api/v1/admin/refresh_remotes")
+            response = client.post("/api/v1/admin/refresh_versions")
 
 
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
 
 
-    def test_refresh_remotes_invalid_token(self, client):
+    def test_refresh_versions_invalid_token(self, client):
         """Test refresh with invalid token - should fail."""
         """Test refresh with invalid token - should fail."""
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
             response = client.post(
             response = client.post(
-                "/api/v1/admin/refresh_remotes",
+                "/api/v1/admin/refresh_versions",
                 headers={"Authorization": "Bearer invalid-token-xyz"}
                 headers={"Authorization": "Bearer invalid-token-xyz"}
             )
             )
 
 
@@ -79,31 +79,31 @@ class TestAdminRefreshRemotesEndpoint:
         assert "detail" in data
         assert "detail" in data
         assert "Invalid authentication token" in data["detail"]
         assert "Invalid authentication token" in data["detail"]
 
 
-    def test_refresh_remotes_malformed_auth_header(self, client):
+    def test_refresh_versions_malformed_auth_header(self, client):
         """Test refresh with malformed authorization header."""
         """Test refresh with malformed authorization header."""
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
             response = client.post(
             response = client.post(
-                "/api/v1/admin/refresh_remotes",
-                headers={"Authorization": "test-remote-reload-token-12345"}
+                "/api/v1/admin/refresh_versions",
+                headers={"Authorization": "test-admin-token-12345"}
             )
             )
 
 
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
 
 
-    def test_refresh_remotes_empty_token(self, client):
+    def test_refresh_versions_empty_token(self, client):
         """Test refresh with empty token."""
         """Test refresh with empty token."""
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
             response = client.post(
             response = client.post(
-                "/api/v1/admin/refresh_remotes",
+                "/api/v1/admin/refresh_versions",
                 headers={"Authorization": "Bearer "}
                 headers={"Authorization": "Bearer "}
             )
             )
 
 
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
         assert response.status_code == status.HTTP_401_UNAUTHORIZED
 
 
-    def test_refresh_remotes_method_not_allowed(self, client):
+    def test_refresh_versions_method_not_allowed(self, client):
         """Test that only POST method is allowed."""
         """Test that only POST method is allowed."""
         disallowed_methods = [
         disallowed_methods = [
             ("GET", client.get),
             ("GET", client.get),
@@ -113,11 +113,11 @@ class TestAdminRefreshRemotesEndpoint:
         ]
         ]
 
 
         mock_settings = Mock()
         mock_settings = Mock()
-        mock_settings.remote_reload_token = self.TEST_TOKEN
+        mock_settings.admin_token = self.TEST_TOKEN
         with self.override_settings(client, mock_settings):
         with self.override_settings(client, mock_settings):
             for method_name, method_func in disallowed_methods:
             for method_name, method_func in disallowed_methods:
                 response = method_func(
                 response = method_func(
-                    "/api/v1/admin/refresh_remotes",
+                    "/api/v1/admin/refresh_versions",
                     headers=self.AUTH_HEADERS
                     headers=self.AUTH_HEADERS
                 )
                 )
                 assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED, \
                 assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED, \

+ 17 - 17
tests/web/test_admin_service.py

@@ -12,46 +12,46 @@ class TestAdminService:
     @pytest.mark.asyncio
     @pytest.mark.asyncio
     async def test_verify_token_success(self):
     async def test_verify_token_success(self):
         """Test successful token verification."""
         """Test successful token verification."""
-        admin_service = AdminService(remote_reload_token="valid-token")
-        result = await admin_service.verify_remote_reload_token("valid-token")
+        admin_service = AdminService(admin_token="valid-token")
+        result = await admin_service.verify_admin_token("valid-token")
         assert result is True
         assert result is True
 
 
     @pytest.mark.asyncio
     @pytest.mark.asyncio
     async def test_verify_token_failure(self):
     async def test_verify_token_failure(self):
         """Test token verification with incorrect token."""
         """Test token verification with incorrect token."""
-        admin_service = AdminService(remote_reload_token="valid-token")
-        result = await admin_service.verify_remote_reload_token("invalid-token")
+        admin_service = AdminService(admin_token="valid-token")
+        result = await admin_service.verify_admin_token("invalid-token")
         assert result is False
         assert result is False
 
 
     @pytest.mark.asyncio
     @pytest.mark.asyncio
-    async def test_refresh_remotes_success(self, mock_versions_fetcher):
-        """Test successful refresh of remote metadata."""
+    async def test_refresh_versions_success(self, mock_versions_manager):
+        """Test successful refresh of version metadata."""
         admin_service = AdminService(
         admin_service = AdminService(
-            remote_reload_token="some-token",
-            versions_fetcher=mock_versions_fetcher
+            admin_token="some-token",
+            versions_manager=mock_versions_manager
         )
         )
-        remotes = await admin_service.refresh_remotes()
+        remotes = await admin_service.refresh_versions()
 
 
         assert len(remotes) == 2
         assert len(remotes) == 2
         assert "test-remote-1" in remotes
         assert "test-remote-1" in remotes
         assert "test-remote-2" in remotes
         assert "test-remote-2" in remotes
 
 
-        mock_versions_fetcher.reload_remotes_json.assert_called_once()
-        mock_versions_fetcher.get_all_remotes_info.assert_called_once()
+        mock_versions_manager.refresh_all.assert_called_once()
+        mock_versions_manager.get_all_remotes_info.assert_called_once()
 
 
     @pytest.mark.asyncio
     @pytest.mark.asyncio
-    async def test_refresh_remotes_empty_result(self):
+    async def test_refresh_versions_empty_result(self):
         """Test refresh when no remotes are configured."""
         """Test refresh when no remotes are configured."""
         mock_fetcher = Mock()
         mock_fetcher = Mock()
-        mock_fetcher.reload_remotes_json = Mock()
+        mock_fetcher.refresh_all = Mock()
         mock_fetcher.get_all_remotes_info = Mock(return_value=[])
         mock_fetcher.get_all_remotes_info = Mock(return_value=[])
 
 
         admin_service = AdminService(
         admin_service = AdminService(
-            remote_reload_token="some-token",
-            versions_fetcher=mock_fetcher
+            admin_token="some-token",
+            versions_manager=mock_fetcher
         )
         )
 
 
-        remotes = await admin_service.refresh_remotes()
+        remotes = await admin_service.refresh_versions()
 
 
         assert len(remotes) == 0
         assert len(remotes) == 0
-        mock_fetcher.reload_remotes_json.assert_called_once()
+        mock_fetcher.refresh_all.assert_called_once()

+ 12 - 13
tests/web/test_builds_service.py

@@ -7,7 +7,7 @@ from unittest.mock import Mock, MagicMock
 
 
 import build_manager as bm
 import build_manager as bm
 from metadata_manager import RemoteInfo as ManagerRemoteInfo
 from metadata_manager import RemoteInfo as ManagerRemoteInfo
-from metadata_manager.versions_fetcher import RemoteInfo, VersionInfo
+from metadata_manager import RemoteInfo, VersionInfo
 from web.schemas import BuildRequest
 from web.schemas import BuildRequest
 from web.services.builds import BuildsService
 from web.services.builds import BuildsService
 
 
@@ -15,14 +15,14 @@ from web.services.builds import BuildsService
 @pytest.fixture
 @pytest.fixture
 def service(
 def service(
     mock_build_manager,
     mock_build_manager,
-    mock_versions_fetcher,
+    mock_versions_manager,
     mock_ap_src_metadata_fetcher,
     mock_ap_src_metadata_fetcher,
     mock_git_repo,
     mock_git_repo,
     mock_vehicles_manager,
     mock_vehicles_manager,
 ):
 ):
     """Create a BuildsService instance with mocked dependencies."""
     """Create a BuildsService instance with mocked dependencies."""
-    mock_versions_fetcher.get_version_info.return_value = make_version_info()
-    mock_versions_fetcher.get_remote_info.return_value = RemoteInfo(
+    mock_versions_manager.get_version_info.return_value = make_version_info()
+    mock_versions_manager.get_remote_info.return_value = RemoteInfo(
         name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"
         name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"
     )
     )
     mock_ap_src_metadata_fetcher.get_boards.return_value = ["MatekH743", "CubeOrange"]
     mock_ap_src_metadata_fetcher.get_boards.return_value = ["MatekH743", "CubeOrange"]
@@ -37,11 +37,10 @@ def service(
     mock_vehicles_manager.get_vehicle_by_id = Mock(
     mock_vehicles_manager.get_vehicle_by_id = Mock(
         side_effect=lambda vid: vehicles.get(vid)
         side_effect=lambda vid: vehicles.get(vid)
     )
     )
-    mock_vehicles_manager.get_vehicle_names = Mock(return_value=[v.name for v in vehicles.values()])
 
 
     return BuildsService(
     return BuildsService(
         build_manager=mock_build_manager,
         build_manager=mock_build_manager,
-        versions_fetcher=mock_versions_fetcher,
+        versions_manager=mock_versions_manager,
         ap_src_metadata_fetcher=mock_ap_src_metadata_fetcher,
         ap_src_metadata_fetcher=mock_ap_src_metadata_fetcher,
         repo=mock_git_repo,
         repo=mock_git_repo,
         vehicles_manager=mock_vehicles_manager,
         vehicles_manager=mock_vehicles_manager,
@@ -179,10 +178,10 @@ class TestBuildsService:
             service.create_build(request)
             service.create_build(request)
 
 
     def test_create_build_raises_value_error_for_invalid_version(
     def test_create_build_raises_value_error_for_invalid_version(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """ValueError is raised when the version_id is not found."""
         """ValueError is raised when the version_id is not found."""
-        mock_versions_fetcher.get_version_info.return_value = None
+        mock_versions_manager.get_version_info.return_value = None
         request = BuildRequest(
         request = BuildRequest(
             vehicle_id="copter",
             vehicle_id="copter",
             board_id="MatekH743",
             board_id="MatekH743",
@@ -194,10 +193,10 @@ class TestBuildsService:
             service.create_build(request)
             service.create_build(request)
 
 
     def test_create_build_queries_version_info_with_correct_params(
     def test_create_build_queries_version_info_with_correct_params(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """get_version_info is called with the correct vehicle_id and version_id."""
         """get_version_info is called with the correct vehicle_id and version_id."""
-        mock_versions_fetcher.get_version_info.return_value = None
+        mock_versions_manager.get_version_info.return_value = None
         request = BuildRequest(
         request = BuildRequest(
             vehicle_id="plane",
             vehicle_id="plane",
             board_id="CubeOrange",
             board_id="CubeOrange",
@@ -208,16 +207,16 @@ class TestBuildsService:
         with pytest.raises(ValueError):
         with pytest.raises(ValueError):
             service.create_build(request)
             service.create_build(request)
 
 
-        mock_versions_fetcher.get_version_info.assert_called_once_with(
+        mock_versions_manager.get_version_info.assert_called_once_with(
             vehicle_id="plane",
             vehicle_id="plane",
             version_id="plane-4.4.0-stable",
             version_id="plane-4.4.0-stable",
         )
         )
 
 
     def test_create_build_raises_value_error_when_remote_not_found(
     def test_create_build_raises_value_error_when_remote_not_found(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """ValueError is raised when the remote is not found."""
         """ValueError is raised when the remote is not found."""
-        mock_versions_fetcher.get_remote_info.return_value = None
+        mock_versions_manager.get_remote_info.return_value = None
         request = BuildRequest(
         request = BuildRequest(
             vehicle_id="some-vehicle",
             vehicle_id="some-vehicle",
             board_id="some-board",
             board_id="some-board",

+ 14 - 14
tests/web/test_config.py

@@ -44,27 +44,27 @@ class TestSettings:
             assert settings.enable_inbuilt_builder is False
             assert settings.enable_inbuilt_builder is False
 
 
 
 
-class TestRemoteReloadToken:
-    """Test suite for remote_reload_token property."""
+class TestAdminToken:
+    """Test suite for admin_token property."""
 
 
     def test_token_from_file(self, tmp_path):
     def test_token_from_file(self, tmp_path):
         """Test that token is read from file when it exists."""
         """Test that token is read from file when it exists."""
         secrets_dir = tmp_path / 'secrets'
         secrets_dir = tmp_path / 'secrets'
         secrets_dir.mkdir()
         secrets_dir.mkdir()
-        token_file = secrets_dir / 'reload_token'
+        token_file = secrets_dir / 'admin_token'
 
 
         expected_token = "test-token-from-file"
         expected_token = "test-token-from-file"
         token_file.write_text(f"  {expected_token}  \n")  # Test whitespace stripping
         token_file.write_text(f"  {expected_token}  \n")  # Test whitespace stripping
 
 
         with patch.dict(os.environ, {"CBS_BASEDIR": str(tmp_path)}, clear=True):
         with patch.dict(os.environ, {"CBS_BASEDIR": str(tmp_path)}, clear=True):
             settings = Settings()
             settings = Settings()
-            assert settings.remote_reload_token == expected_token
+            assert settings.admin_token == expected_token
 
 
     def test_token_file_takes_precedence_over_env(self, tmp_path):
     def test_token_file_takes_precedence_over_env(self, tmp_path):
         """Test that token from file takes precedence over environment variable."""
         """Test that token from file takes precedence over environment variable."""
         secrets_dir = tmp_path / 'secrets'
         secrets_dir = tmp_path / 'secrets'
         secrets_dir.mkdir()
         secrets_dir.mkdir()
-        token_file = secrets_dir / 'reload_token'
+        token_file = secrets_dir / 'admin_token'
 
 
         file_token = "token-from-file"
         file_token = "token-from-file"
         env_token = "token-from-env"
         env_token = "token-from-env"
@@ -73,10 +73,10 @@ class TestRemoteReloadToken:
 
 
         with patch.dict(os.environ, {
         with patch.dict(os.environ, {
             "CBS_BASEDIR": str(tmp_path),
             "CBS_BASEDIR": str(tmp_path),
-            "CBS_REMOTES_RELOAD_TOKEN": env_token
+            "CBS_ADMIN_TOKEN": env_token
         }, clear=True):
         }, clear=True):
             settings = Settings()
             settings = Settings()
-            assert settings.remote_reload_token == file_token
+            assert settings.admin_token == file_token
 
 
     def test_token_from_env_when_file_not_found(self, tmp_path):
     def test_token_from_env_when_file_not_found(self, tmp_path):
         """Test that token falls back to environment variable when file doesn't exist."""
         """Test that token falls back to environment variable when file doesn't exist."""
@@ -84,10 +84,10 @@ class TestRemoteReloadToken:
 
 
         with patch.dict(os.environ, {
         with patch.dict(os.environ, {
             "CBS_BASEDIR": str(tmp_path),
             "CBS_BASEDIR": str(tmp_path),
-            "CBS_REMOTES_RELOAD_TOKEN": expected_token
+            "CBS_ADMIN_TOKEN": expected_token
         }, clear=True):
         }, clear=True):
             settings = Settings()
             settings = Settings()
-            assert settings.remote_reload_token == expected_token
+            assert settings.admin_token == expected_token
 
 
     def test_token_from_env_on_file_read_error(self, tmp_path):
     def test_token_from_env_on_file_read_error(self, tmp_path):
         """Test that token falls back to env var when file cannot be read."""
         """Test that token falls back to env var when file cannot be read."""
@@ -95,23 +95,23 @@ class TestRemoteReloadToken:
 
 
         with patch.dict(os.environ, {
         with patch.dict(os.environ, {
             "CBS_BASEDIR": str(tmp_path),
             "CBS_BASEDIR": str(tmp_path),
-            "CBS_REMOTES_RELOAD_TOKEN": env_token
+            "CBS_ADMIN_TOKEN": env_token
         }, clear=True):
         }, clear=True):
             with patch("builtins.open", side_effect=PermissionError("No access")):
             with patch("builtins.open", side_effect=PermissionError("No access")):
                 settings = Settings()
                 settings = Settings()
-                assert settings.remote_reload_token == env_token
+                assert settings.admin_token == env_token
 
 
     def test_token_none_when_not_configured(self, tmp_path):
     def test_token_none_when_not_configured(self, tmp_path):
         """Test that token is None when neither file nor env var is set."""
         """Test that token is None when neither file nor env var is set."""
         with patch.dict(os.environ, {"CBS_BASEDIR": str(tmp_path)}, clear=True):
         with patch.dict(os.environ, {"CBS_BASEDIR": str(tmp_path)}, clear=True):
             settings = Settings()
             settings = Settings()
-            assert settings.remote_reload_token is None
+            assert settings.admin_token is None
 
 
     def test_token_none_when_env_is_empty_string(self, tmp_path):
     def test_token_none_when_env_is_empty_string(self, tmp_path):
         """Test that token is None when env var is empty string."""
         """Test that token is None when env var is empty string."""
         with patch.dict(os.environ, {
         with patch.dict(os.environ, {
             "CBS_BASEDIR": str(tmp_path),
             "CBS_BASEDIR": str(tmp_path),
-            "CBS_REMOTES_RELOAD_TOKEN": ""
+            "CBS_ADMIN_TOKEN": ""
         }, clear=True):
         }, clear=True):
             settings = Settings()
             settings = Settings()
-            assert settings.remote_reload_token is None
+            assert settings.admin_token is None

+ 99 - 103
tests/web/test_vehicles_service.py

@@ -4,16 +4,19 @@ Tests for the Vehicles Service.
 import pytest
 import pytest
 from unittest.mock import Mock
 from unittest.mock import Mock
 
 
-from metadata_manager import Vehicle
-from metadata_manager.versions_fetcher import VersionInfo, RemoteInfo
+from metadata_manager import (
+    RemoteInfo,
+    Vehicle,
+    VersionInfo,
+)
 from web.services.vehicles import VehiclesService
 from web.services.vehicles import VehiclesService
 
 
 
 
 @pytest.fixture
 @pytest.fixture
-def service(mock_vehicles_manager, mock_versions_fetcher, mock_ap_src_metadata_fetcher, mock_git_repo):
+def service(mock_vehicles_manager, mock_versions_manager, mock_ap_src_metadata_fetcher, mock_git_repo):
     return VehiclesService(
     return VehiclesService(
         vehicle_manager=mock_vehicles_manager,
         vehicle_manager=mock_vehicles_manager,
-        versions_fetcher=mock_versions_fetcher,
+        versions_manager=mock_versions_manager,
         ap_src_metadata_fetcher=mock_ap_src_metadata_fetcher,
         ap_src_metadata_fetcher=mock_ap_src_metadata_fetcher,
         repo=mock_git_repo,
         repo=mock_git_repo,
     )
     )
@@ -31,14 +34,12 @@ class TestVehiclesService:
                 id="copter",
                 id="copter",
                 name="Copter",
                 name="Copter",
                 ap_source_subdir="ArduCopter",
                 ap_source_subdir="ArduCopter",
-                fw_server_vehicle_sdir="Copter",
                 waf_build_command="copter"
                 waf_build_command="copter"
             ),
             ),
             Vehicle(
             Vehicle(
                 id="plane",
                 id="plane",
                 name="Plane",
                 name="Plane",
                 ap_source_subdir="ArduPlane",
                 ap_source_subdir="ArduPlane",
-                fw_server_vehicle_sdir="Plane",
                 waf_build_command="plane"
                 waf_build_command="plane"
             ),
             ),
         ]
         ]
@@ -64,7 +65,6 @@ class TestVehiclesService:
                 id="copter",
                 id="copter",
                 name="Copter",
                 name="Copter",
                 ap_source_subdir="ArduCopter",
                 ap_source_subdir="ArduCopter",
-                fw_server_vehicle_sdir="Copter",
                 waf_build_command="copter"
                 waf_build_command="copter"
             ),
             ),
         ]
         ]
@@ -80,21 +80,18 @@ class TestVehiclesService:
                 id="plane",
                 id="plane",
                 name="Plane",
                 name="Plane",
                 ap_source_subdir="ArduPlane",
                 ap_source_subdir="ArduPlane",
-                fw_server_vehicle_sdir="Plane",
                 waf_build_command="plane"
                 waf_build_command="plane"
             ),
             ),
             Vehicle(
             Vehicle(
                 id="copter",
                 id="copter",
                 name="Copter",
                 name="Copter",
                 ap_source_subdir="ArduCopter",
                 ap_source_subdir="ArduCopter",
-                fw_server_vehicle_sdir="Copter",
                 waf_build_command="copter"
                 waf_build_command="copter"
             ),
             ),
             Vehicle(
             Vehicle(
                 id="rover",
                 id="rover",
                 name="Rover",
                 name="Rover",
                 ap_source_subdir="ArduRover",
                 ap_source_subdir="ArduRover",
-                fw_server_vehicle_sdir="Rover",
                 waf_build_command="rover"
                 waf_build_command="rover"
             ),
             ),
         ]
         ]
@@ -118,7 +115,6 @@ class TestVehiclesService:
             id="copter",
             id="copter",
             name="Copter",
             name="Copter",
             ap_source_subdir="ArduCopter",
             ap_source_subdir="ArduCopter",
-            fw_server_vehicle_sdir="Copter",
             waf_build_command="copter"
             waf_build_command="copter"
         )
         )
         vehicle = service.get_vehicle("copter")
         vehicle = service.get_vehicle("copter")
@@ -143,16 +139,16 @@ class TestVehiclesService:
 
 
     # Tests for get_versions
     # Tests for get_versions
 
 
-    def test_get_versions_empty(self, service, mock_versions_fetcher):
+    def test_get_versions_empty(self, service, mock_versions_manager):
         """Test that an empty list is returned when no versions exist."""
         """Test that an empty list is returned when no versions exist."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = []
+        mock_versions_manager.get_versions_for_vehicle.return_value = []
         versions = service.get_versions("copter")
         versions = service.get_versions("copter")
 
 
         assert versions == []
         assert versions == []
 
 
-    def test_get_versions_single(self, service, mock_versions_fetcher):
+    def test_get_versions_single(self, service, mock_versions_manager):
         """Test fetching versions when only one version exists."""
         """Test fetching versions when only one version exists."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/heads/master",
                 commit_ref="refs/heads/master",
@@ -165,9 +161,9 @@ class TestVehiclesService:
 
 
         assert len(versions) == 1
         assert len(versions) == 1
 
 
-    def test_get_versions_many(self, service, mock_versions_fetcher):
+    def test_get_versions_many(self, service, mock_versions_manager):
         """Test fetching versions when multiple versions exist."""
         """Test fetching versions when multiple versions exist."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/heads/master",
                 commit_ref="refs/heads/master",
@@ -194,9 +190,9 @@ class TestVehiclesService:
 
 
         assert len(versions) == 3
         assert len(versions) == 3
 
 
-    def test_get_versions_sorted_by_name(self, service, mock_versions_fetcher):
+    def test_get_versions_sorted_by_name(self, service, mock_versions_manager):
         """Test that versions are returned sorted by their display name."""
         """Test that versions are returned sorted by their display name."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -225,21 +221,21 @@ class TestVehiclesService:
         assert names == sorted(names)
         assert names == sorted(names)
 
 
     def test_get_versions_calls_fetcher_once_with_correct_vehicle_id(
     def test_get_versions_calls_fetcher_once_with_correct_vehicle_id(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that get_versions calls the fetcher exactly once with the correct vehicle_id."""
         """Test that get_versions calls the fetcher exactly once with the correct vehicle_id."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = []
+        mock_versions_manager.get_versions_for_vehicle.return_value = []
         service.get_versions("copter")
         service.get_versions("copter")
 
 
-        mock_versions_fetcher.get_versions_for_vehicle.assert_called_once_with(
+        mock_versions_manager.get_versions_for_vehicle.assert_called_once_with(
             vehicle_id="copter"
             vehicle_id="copter"
         )
         )
 
 
     def test_get_versions_type_filter_keeps_matching(
     def test_get_versions_type_filter_keeps_matching(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that type_filter returns only versions of the specified type."""
         """Test that type_filter returns only versions of the specified type."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -268,10 +264,10 @@ class TestVehiclesService:
         assert versions[0].type == "stable"
         assert versions[0].type == "stable"
 
 
     def test_get_versions_type_filter_excludes_non_matching(
     def test_get_versions_type_filter_excludes_non_matching(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that type_filter excludes versions that do not match."""
         """Test that type_filter excludes versions that do not match."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -292,10 +288,10 @@ class TestVehiclesService:
         assert versions == []
         assert versions == []
 
 
     def test_get_versions_type_filter_none_returns_all(
     def test_get_versions_type_filter_none_returns_all(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that passing no type_filter returns all versions."""
         """Test that passing no type_filter returns all versions."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -323,10 +319,10 @@ class TestVehiclesService:
         assert len(versions) == 3
         assert len(versions) == 3
 
 
     def test_get_versions_type_filter_multiple_matches(
     def test_get_versions_type_filter_multiple_matches(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that type_filter returns all versions matching the type when there are multiple."""
         """Test that type_filter returns all versions matching the type when there are multiple."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.4.0",
                 commit_ref="refs/tags/Copter-4.4.0",
@@ -355,10 +351,10 @@ class TestVehiclesService:
         assert all(v.type == "stable" for v in versions)
         assert all(v.type == "stable" for v in versions)
 
 
     def test_get_versions_latest_name_format(
     def test_get_versions_latest_name_format(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that latest versions have the correct display name format."""
         """Test that latest versions have the correct display name format."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/heads/master",
                 commit_ref="refs/heads/master",
@@ -372,10 +368,10 @@ class TestVehiclesService:
         assert versions[0].name == "Latest (ardupilot)"
         assert versions[0].name == "Latest (ardupilot)"
 
 
     def test_get_versions_non_latest_name_format(
     def test_get_versions_non_latest_name_format(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that non-latest versions have the correct display name format."""
         """Test that non-latest versions have the correct display name format."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -390,7 +386,7 @@ class TestVehiclesService:
 
 
     # Tests for get_version
     # Tests for get_version
 
 
-    def test_get_version_found(self, service, mock_versions_fetcher):
+    def test_get_version_found(self, service, mock_versions_manager):
         """Test that the correct version is returned when it exists."""
         """Test that the correct version is returned when it exists."""
         version_info = VersionInfo(
         version_info = VersionInfo(
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
@@ -399,16 +395,16 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [version_info]
+        mock_versions_manager.get_versions_for_vehicle.return_value = [version_info]
 
 
         result = service.get_version("copter", version_info.version_id)
         result = service.get_version("copter", version_info.version_id)
 
 
         assert result is not None
         assert result is not None
         assert result.id == version_info.version_id
         assert result.id == version_info.version_id
 
 
-    def test_get_version_not_found(self, service, mock_versions_fetcher):
+    def test_get_version_not_found(self, service, mock_versions_manager):
         """Test that None is returned when the version does not exist."""
         """Test that None is returned when the version does not exist."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             VersionInfo(
             VersionInfo(
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
                 commit_ref="refs/tags/Copter-4.5.0",
                 commit_ref="refs/tags/Copter-4.5.0",
@@ -422,15 +418,15 @@ class TestVehiclesService:
 
 
         assert result is None
         assert result is None
 
 
-    def test_get_version_no_versions_available(self, service, mock_versions_fetcher):
+    def test_get_version_no_versions_available(self, service, mock_versions_manager):
         """Test that None is returned when there are no versions at all."""
         """Test that None is returned when there are no versions at all."""
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = []
+        mock_versions_manager.get_versions_for_vehicle.return_value = []
 
 
         result = service.get_version("copter", "any-version-id")
         result = service.get_version("copter", "any-version-id")
 
 
         assert result is None
         assert result is None
 
 
-    def test_get_version_returns_correct_match_among_many(self, service, mock_versions_fetcher):
+    def test_get_version_returns_correct_match_among_many(self, service, mock_versions_manager):
         """Test that only the matching version is returned when multiple exist."""
         """Test that only the matching version is returned when multiple exist."""
         stable_info = VersionInfo(
         stable_info = VersionInfo(
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
@@ -453,7 +449,7 @@ class TestVehiclesService:
             version_number="NA",
             version_number="NA",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_versions_for_vehicle.return_value = [
+        mock_versions_manager.get_versions_for_vehicle.return_value = [
             stable_info, beta_info, latest_info,
             stable_info, beta_info, latest_info,
         ]
         ]
 
 
@@ -465,29 +461,29 @@ class TestVehiclesService:
 
 
     # Tests for get_boards
     # Tests for get_boards
 
 
-    def test_get_boards_version_not_found_returns_empty(self, service, mock_versions_fetcher):
+    def test_get_boards_version_not_found_returns_empty(self, service, mock_versions_manager):
         """Test that an empty list is returned when the version does not exist."""
         """Test that an empty list is returned when the version does not exist."""
-        mock_versions_fetcher.get_version_info.return_value = None
+        mock_versions_manager.get_version_info.return_value = None
 
 
         result = service.get_boards("copter", "nonexistent-version-id")
         result = service.get_boards("copter", "nonexistent-version-id")
 
 
         assert result == []
         assert result == []
 
 
     def test_get_boards_version_info_queried_with_correct_params(
     def test_get_boards_version_info_queried_with_correct_params(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that get_version_info is called with the correct vehicle and version IDs."""
         """Test that get_version_info is called with the correct vehicle and version IDs."""
-        mock_versions_fetcher.get_version_info.return_value = None
+        mock_versions_manager.get_version_info.return_value = None
 
 
         service.get_boards("copter", "some-version-id")
         service.get_boards("copter", "some-version-id")
 
 
-        mock_versions_fetcher.get_version_info.assert_called_once_with(
+        mock_versions_manager.get_version_info.assert_called_once_with(
             vehicle_id="copter",
             vehicle_id="copter",
             version_id="some-version-id",
             version_id="some-version-id",
         )
         )
 
 
     def test_get_boards_empty(
     def test_get_boards_empty(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that an empty list is returned when there are no boards for a version."""
         """Test that an empty list is returned when there are no boards for a version."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -497,7 +493,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = []
         mock_ap_src_metadata_fetcher.get_boards.return_value = []
 
 
         result = service.get_boards("copter", version_info.version_id)
         result = service.get_boards("copter", version_info.version_id)
@@ -505,7 +501,7 @@ class TestVehiclesService:
         assert result == []
         assert result == []
 
 
     def test_get_boards_single(
     def test_get_boards_single(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a single board is returned correctly."""
         """Test that a single board is returned correctly."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -515,7 +511,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed"]
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed"]
 
 
         result = service.get_boards("copter", version_info.version_id)
         result = service.get_boards("copter", version_info.version_id)
@@ -525,7 +521,7 @@ class TestVehiclesService:
         assert result[0].name == "CubeRed"
         assert result[0].name == "CubeRed"
 
 
     def test_get_boards_many(
     def test_get_boards_many(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that multiple boards are returned correctly."""
         """Test that multiple boards are returned correctly."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -535,7 +531,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = [
         mock_ap_src_metadata_fetcher.get_boards.return_value = [
             "CubeRed", "CubeOrange", "MatekF405",
             "CubeRed", "CubeOrange", "MatekF405",
         ]
         ]
@@ -546,7 +542,7 @@ class TestVehiclesService:
         assert [b.id for b in result] == ["CubeRed", "CubeOrange", "MatekF405"]
         assert [b.id for b in result] == ["CubeRed", "CubeOrange", "MatekF405"]
 
 
     def test_get_boards_sets_correct_vehicle_and_version_ids(
     def test_get_boards_sets_correct_vehicle_and_version_ids(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that returned boards carry the correct vehicle_id and version_id."""
         """Test that returned boards carry the correct vehicle_id and version_id."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -556,7 +552,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed"]
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed"]
 
 
         result = service.get_boards("copter", version_info.version_id)
         result = service.get_boards("copter", version_info.version_id)
@@ -565,7 +561,7 @@ class TestVehiclesService:
         assert result[0].version_id == version_info.version_id
         assert result[0].version_id == version_info.version_id
 
 
     def test_get_boards_fetcher_called_with_correct_params(
     def test_get_boards_fetcher_called_with_correct_params(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that the metadata fetcher is called with remote name, commit ref, and vehicle ID from version info."""
         """Test that the metadata fetcher is called with remote name, commit ref, and vehicle ID from version info."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -575,7 +571,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = []
         mock_ap_src_metadata_fetcher.get_boards.return_value = []
 
 
         service.get_boards("copter", version_info.version_id)
         service.get_boards("copter", version_info.version_id)
@@ -588,7 +584,7 @@ class TestVehiclesService:
 
 
     # Tests for get_board
     # Tests for get_board
 
 
-    def test_get_board_found(self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher):
+    def test_get_board_found(self, service, mock_versions_manager, mock_ap_src_metadata_fetcher):
         """Test that the correct board is returned when it exists."""
         """Test that the correct board is returned when it exists."""
         version_info = VersionInfo(
         version_info = VersionInfo(
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
@@ -597,7 +593,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed", "CubeOrange"]
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed", "CubeOrange"]
 
 
         result = service.get_board("copter", version_info.version_id, "CubeRed")
         result = service.get_board("copter", version_info.version_id, "CubeRed")
@@ -608,7 +604,7 @@ class TestVehiclesService:
         assert result.vehicle_id == "copter"
         assert result.vehicle_id == "copter"
         assert result.version_id == version_info.version_id
         assert result.version_id == version_info.version_id
 
 
-    def test_get_board_not_found(self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher):
+    def test_get_board_not_found(self, service, mock_versions_manager, mock_ap_src_metadata_fetcher):
         """Test that None is returned when the board does not exist."""
         """Test that None is returned when the board does not exist."""
         version_info = VersionInfo(
         version_info = VersionInfo(
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
             remote_info=RemoteInfo(name="ardupilot", url="https://github.com/ArduPilot/ardupilot.git"),
@@ -617,7 +613,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed", "CubeOrange"]
         mock_ap_src_metadata_fetcher.get_boards.return_value = ["CubeRed", "CubeOrange"]
 
 
         result = service.get_board("copter", version_info.version_id, "NonExistentBoard")
         result = service.get_board("copter", version_info.version_id, "NonExistentBoard")
@@ -625,7 +621,7 @@ class TestVehiclesService:
         assert result is None
         assert result is None
 
 
     def test_get_board_returns_correct_match_among_many(
     def test_get_board_returns_correct_match_among_many(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that only the matching board is returned when multiple boards exist."""
         """Test that only the matching board is returned when multiple boards exist."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -635,7 +631,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_boards.return_value = [
         mock_ap_src_metadata_fetcher.get_boards.return_value = [
             "CubeRed", "CubeOrange", "MatekF405",
             "CubeRed", "CubeOrange", "MatekF405",
         ]
         ]
@@ -648,17 +644,17 @@ class TestVehiclesService:
     # Tests for get_features
     # Tests for get_features
 
 
     def test_get_features_version_not_found_returns_empty(
     def test_get_features_version_not_found_returns_empty(
-        self, service, mock_versions_fetcher
+        self, service, mock_versions_manager
     ):
     ):
         """Test that an empty list is returned when the version does not exist."""
         """Test that an empty list is returned when the version does not exist."""
-        mock_versions_fetcher.get_version_info.return_value = None
+        mock_versions_manager.get_version_info.return_value = None
 
 
         result = service.get_features("copter", "nonexistent-version-id", "CubeRed")
         result = service.get_features("copter", "nonexistent-version-id", "CubeRed")
 
 
         assert result == []
         assert result == []
 
 
     def test_get_features_zero_options_returns_empty(
     def test_get_features_zero_options_returns_empty(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that an empty list is returned when there are no build options."""
         """Test that an empty list is returned when there are no build options."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -668,7 +664,7 @@ class TestVehiclesService:
             version_number="4.5.0",
             version_number="4.5.0",
             ap_build_artifacts_url=None,
             ap_build_artifacts_url=None,
         )
         )
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = []
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = []
 
 
         result = service.get_features("copter", version_info.version_id, "CubeRed")
         result = service.get_features("copter", version_info.version_id, "CubeRed")
@@ -676,7 +672,7 @@ class TestVehiclesService:
         assert result == []
         assert result == []
 
 
     def test_get_features_one_option(
     def test_get_features_one_option(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a single feature is returned correctly."""
         """Test that a single feature is returned correctly."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -693,7 +689,7 @@ class TestVehiclesService:
         opt.description = ""
         opt.description = ""
         opt.default = 1
         opt.default = 1
         opt.dependency = None
         opt.dependency = None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -704,7 +700,7 @@ class TestVehiclesService:
         assert result[0].name == "HAL_LOGGING_ENABLED"
         assert result[0].name == "HAL_LOGGING_ENABLED"
 
 
     def test_get_features_many_options(
     def test_get_features_many_options(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that all features are returned when multiple options exist."""
         """Test that all features are returned when multiple options exist."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -723,7 +719,7 @@ class TestVehiclesService:
         opt_sensors = Mock()
         opt_sensors = Mock()
         opt_sensors.label, opt_sensors.define, opt_sensors.category = "HAL_BEACON_ENABLED", "HAL_BEACON_ENABLED", "Sensors"
         opt_sensors.label, opt_sensors.define, opt_sensors.category = "HAL_BEACON_ENABLED", "HAL_BEACON_ENABLED", "Sensors"
         opt_sensors.description, opt_sensors.default, opt_sensors.dependency = "", 1, None
         opt_sensors.description, opt_sensors.default, opt_sensors.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf, opt_sensors]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf, opt_sensors]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -732,7 +728,7 @@ class TestVehiclesService:
         assert len(result) == 3
         assert len(result) == 3
 
 
     def test_get_features_sorted_by_category(
     def test_get_features_sorted_by_category(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that features are sorted by category name."""
         """Test that features are sorted by category name."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -751,7 +747,7 @@ class TestVehiclesService:
         opt_m = Mock()
         opt_m = Mock()
         opt_m.label, opt_m.define, opt_m.category = "FEATURE_M", "DEFINE_M", "Logging"
         opt_m.label, opt_m.define, opt_m.category = "FEATURE_M", "DEFINE_M", "Logging"
         opt_m.description, opt_m.default, opt_m.dependency = "", 1, None
         opt_m.description, opt_m.default, opt_m.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_z, opt_a, opt_m]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_z, opt_a, opt_m]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -760,7 +756,7 @@ class TestVehiclesService:
         assert [f.category.name for f in result] == ["EKF", "Logging", "Sensors"]
         assert [f.category.name for f in result] == ["EKF", "Logging", "Sensors"]
 
 
     def test_get_features_uses_fallback_defaults_when_no_artifacts_url(
     def test_get_features_uses_fallback_defaults_when_no_artifacts_url(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that build-options-py defaults are used when ap_build_artifacts_url is None."""
         """Test that build-options-py defaults are used when ap_build_artifacts_url is None."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -776,7 +772,7 @@ class TestVehiclesService:
         opt_off = Mock()
         opt_off = Mock()
         opt_off.label, opt_off.define, opt_off.category = "FEATURE_OFF", "DEFINE_OFF", "Cat"
         opt_off.label, opt_off.define, opt_off.category = "FEATURE_OFF", "DEFINE_OFF", "Cat"
         opt_off.description, opt_off.default, opt_off.dependency = "", 0, None
         opt_off.description, opt_off.default, opt_off.dependency = "", 0, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_on, opt_off]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_on, opt_off]
 
 
         result = service.get_features("copter", version_info.version_id, "CubeRed")
         result = service.get_features("copter", version_info.version_id, "CubeRed")
@@ -789,7 +785,7 @@ class TestVehiclesService:
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.assert_not_called()
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.assert_not_called()
 
 
     def test_get_features_uses_firmware_server_defaults_when_available(
     def test_get_features_uses_firmware_server_defaults_when_available(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that firmware-server defaults override build-options-py when present."""
         """Test that firmware-server defaults override build-options-py when present."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -805,7 +801,7 @@ class TestVehiclesService:
         opt_b = Mock()
         opt_b = Mock()
         opt_b.label, opt_b.define, opt_b.category = "FEATURE_B", "DEFINE_B", "Cat"
         opt_b.label, opt_b.define, opt_b.category = "FEATURE_B", "DEFINE_B", "Cat"
         opt_b.description, opt_b.default, opt_b.dependency = "", 1, None
         opt_b.description, opt_b.default, opt_b.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b]
         # firmware server says DEFINE_A is disabled, DEFINE_B is enabled
         # firmware server says DEFINE_A is disabled, DEFINE_B is enabled
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = {
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = {
@@ -822,7 +818,7 @@ class TestVehiclesService:
         assert by_id["FEATURE_B"].source == "firmware-server"
         assert by_id["FEATURE_B"].source == "firmware-server"
 
 
     def test_get_features_falls_back_to_defaults_when_firmware_server_returns_none(
     def test_get_features_falls_back_to_defaults_when_firmware_server_returns_none(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that build-options-py fallback is used when firmware server fetch fails."""
         """Test that build-options-py fallback is used when firmware server fetch fails."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -835,7 +831,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, None
         opt.description, opt.default, opt.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -845,7 +841,7 @@ class TestVehiclesService:
         assert result[0].default.source == "build-options-py"
         assert result[0].default.source == "build-options-py"
 
 
     def test_get_features_firmware_server_overrides_only_known_defines(
     def test_get_features_firmware_server_overrides_only_known_defines(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a define absent from firmware-server data falls back to build-options-py."""
         """Test that a define absent from firmware-server data falls back to build-options-py."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -861,7 +857,7 @@ class TestVehiclesService:
         opt_unknown = Mock()
         opt_unknown = Mock()
         opt_unknown.label, opt_unknown.define, opt_unknown.category = "FEATURE_UNKNOWN", "DEFINE_UNKNOWN", "Cat"
         opt_unknown.label, opt_unknown.define, opt_unknown.category = "FEATURE_UNKNOWN", "DEFINE_UNKNOWN", "Cat"
         opt_unknown.description, opt_unknown.default, opt_unknown.dependency = "", 1, None
         opt_unknown.description, opt_unknown.default, opt_unknown.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_known, opt_unknown]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_known, opt_unknown]
         # firmware server only knows about DEFINE_KNOWN
         # firmware server only knows about DEFINE_KNOWN
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = {
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = {
@@ -877,7 +873,7 @@ class TestVehiclesService:
         assert by_id["FEATURE_UNKNOWN"].source == "build-options-py"
         assert by_id["FEATURE_UNKNOWN"].source == "build-options-py"
 
 
     def test_get_features_dependency_none(
     def test_get_features_dependency_none(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a feature with no dependency produces an empty dependencies list."""
         """Test that a feature with no dependency produces an empty dependencies list."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -890,7 +886,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, None
         opt.description, opt.default, opt.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -899,7 +895,7 @@ class TestVehiclesService:
         assert result[0].dependencies == []
         assert result[0].dependencies == []
 
 
     def test_get_features_dependency_single(
     def test_get_features_dependency_single(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a single dependency string is parsed into a one-element list."""
         """Test that a single dependency string is parsed into a one-element list."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -912,7 +908,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE"
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -921,7 +917,7 @@ class TestVehiclesService:
         assert result[0].dependencies == ["DEP_ONE"]
         assert result[0].dependencies == ["DEP_ONE"]
 
 
     def test_get_features_dependency_multiple_comma_separated(
     def test_get_features_dependency_multiple_comma_separated(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a comma-separated dependency string is split into multiple entries."""
         """Test that a comma-separated dependency string is split into multiple entries."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -934,7 +930,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE,DEP_TWO,DEP_THREE"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE,DEP_TWO,DEP_THREE"
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -943,7 +939,7 @@ class TestVehiclesService:
         assert result[0].dependencies == ["DEP_ONE", "DEP_TWO", "DEP_THREE"]
         assert result[0].dependencies == ["DEP_ONE", "DEP_TWO", "DEP_THREE"]
 
 
     def test_get_features_dependency_with_spaces(
     def test_get_features_dependency_with_spaces(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that spaces around dependency labels are stripped."""
         """Test that spaces around dependency labels are stripped."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -956,7 +952,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE , DEP_TWO , DEP_THREE"
         opt.description, opt.default, opt.dependency = "", 1, "DEP_ONE , DEP_TWO , DEP_THREE"
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -965,7 +961,7 @@ class TestVehiclesService:
         assert result[0].dependencies == ["DEP_ONE", "DEP_TWO", "DEP_THREE"]
         assert result[0].dependencies == ["DEP_ONE", "DEP_TWO", "DEP_THREE"]
 
 
     def test_get_features_ids_filled_correctly(
     def test_get_features_ids_filled_correctly(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that vehicle_id, version_id, and board_id are correctly set on each feature."""
         """Test that vehicle_id, version_id, and board_id are correctly set on each feature."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -978,7 +974,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.label, opt.define, opt.category = "FEATURE_A", "DEFINE_A", "Cat"
         opt.description, opt.default, opt.dependency = "", 1, None
         opt.description, opt.default, opt.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -989,7 +985,7 @@ class TestVehiclesService:
         assert result[0].board_id == "CubeRed"
         assert result[0].board_id == "CubeRed"
 
 
     def test_get_features_category_filter_keeps_matching(
     def test_get_features_category_filter_keeps_matching(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that category_id filter returns only features whose category matches."""
         """Test that category_id filter returns only features whose category matches."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1008,7 +1004,7 @@ class TestVehiclesService:
         opt_sensors = Mock()
         opt_sensors = Mock()
         opt_sensors.label, opt_sensors.define, opt_sensors.category = "HAL_BEACON_ENABLED", "HAL_BEACON_ENABLED", "Sensors"
         opt_sensors.label, opt_sensors.define, opt_sensors.category = "HAL_BEACON_ENABLED", "HAL_BEACON_ENABLED", "Sensors"
         opt_sensors.description, opt_sensors.default, opt_sensors.dependency = "", 1, None
         opt_sensors.description, opt_sensors.default, opt_sensors.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf, opt_sensors]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf, opt_sensors]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -1019,7 +1015,7 @@ class TestVehiclesService:
         assert result[0].category.name == "Logging"
         assert result[0].category.name == "Logging"
 
 
     def test_get_features_category_filter_excludes_non_matching(
     def test_get_features_category_filter_excludes_non_matching(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that category_id filter excludes features whose category does not match."""
         """Test that category_id filter excludes features whose category does not match."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1035,7 +1031,7 @@ class TestVehiclesService:
         opt_ekf = Mock()
         opt_ekf = Mock()
         opt_ekf.label, opt_ekf.define, opt_ekf.category = "HAL_NAVEKF3_AVAILABLE", "HAL_NAVEKF3_AVAILABLE", "EKF"
         opt_ekf.label, opt_ekf.define, opt_ekf.category = "HAL_NAVEKF3_AVAILABLE", "HAL_NAVEKF3_AVAILABLE", "EKF"
         opt_ekf.description, opt_ekf.default, opt_ekf.dependency = "", 1, None
         opt_ekf.description, opt_ekf.default, opt_ekf.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_logging, opt_ekf]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -1044,7 +1040,7 @@ class TestVehiclesService:
         assert result == []
         assert result == []
 
 
     def test_get_features_category_filter_no_matches_returns_empty(
     def test_get_features_category_filter_no_matches_returns_empty(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that a category_id with no matching features returns an empty list."""
         """Test that a category_id with no matching features returns an empty list."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1060,7 +1056,7 @@ class TestVehiclesService:
         opt_b = Mock()
         opt_b = Mock()
         opt_b.label, opt_b.define, opt_b.category = "FEATURE_B", "DEFINE_B", "Logging"
         opt_b.label, opt_b.define, opt_b.category = "FEATURE_B", "DEFINE_B", "Logging"
         opt_b.description, opt_b.default, opt_b.dependency = "", 1, None
         opt_b.description, opt_b.default, opt_b.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -1071,7 +1067,7 @@ class TestVehiclesService:
     # Tests for get_feature
     # Tests for get_feature
 
 
     def test_get_feature_found(
     def test_get_feature_found(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that the correct feature is returned when it exists."""
         """Test that the correct feature is returned when it exists."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1084,7 +1080,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "HAL_LOGGING_ENABLED", "HAL_LOGGING_ENABLED", "Logging"
         opt.label, opt.define, opt.category = "HAL_LOGGING_ENABLED", "HAL_LOGGING_ENABLED", "Logging"
         opt.description, opt.default, opt.dependency = "", 1, None
         opt.description, opt.default, opt.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -1095,7 +1091,7 @@ class TestVehiclesService:
         assert result.name == "HAL_LOGGING_ENABLED"
         assert result.name == "HAL_LOGGING_ENABLED"
 
 
     def test_get_feature_not_found(
     def test_get_feature_not_found(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that None is returned when the feature does not exist."""
         """Test that None is returned when the feature does not exist."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1108,7 +1104,7 @@ class TestVehiclesService:
         opt = Mock()
         opt = Mock()
         opt.label, opt.define, opt.category = "HAL_LOGGING_ENABLED", "HAL_LOGGING_ENABLED", "Logging"
         opt.label, opt.define, opt.category = "HAL_LOGGING_ENABLED", "HAL_LOGGING_ENABLED", "Logging"
         opt.description, opt.default, opt.dependency = "", 1, None
         opt.description, opt.default, opt.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
 
 
@@ -1117,7 +1113,7 @@ class TestVehiclesService:
         assert result is None
         assert result is None
 
 
     def test_get_feature_returns_correct_match_among_many(
     def test_get_feature_returns_correct_match_among_many(
-        self, service, mock_versions_fetcher, mock_ap_src_metadata_fetcher
+        self, service, mock_versions_manager, mock_ap_src_metadata_fetcher
     ):
     ):
         """Test that only the matching feature is returned when multiple features exist."""
         """Test that only the matching feature is returned when multiple features exist."""
         version_info = VersionInfo(
         version_info = VersionInfo(
@@ -1136,7 +1132,7 @@ class TestVehiclesService:
         opt_c = Mock()
         opt_c = Mock()
         opt_c.label, opt_c.define, opt_c.category = "FEATURE_C", "DEFINE_C", "Cat"
         opt_c.label, opt_c.define, opt_c.category = "FEATURE_C", "DEFINE_C", "Cat"
         opt_c.description, opt_c.default, opt_c.dependency = "", 1, None
         opt_c.description, opt_c.default, opt_c.dependency = "", 1, None
-        mock_versions_fetcher.get_version_info.return_value = version_info
+        mock_versions_manager.get_version_info.return_value = version_info
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b, opt_c]
         mock_ap_src_metadata_fetcher.get_build_options_at_commit.return_value = [opt_a, opt_b, opt_c]
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None
         mock_ap_src_metadata_fetcher.get_board_defaults_from_fw_server.return_value = None