diff --git a/subiquity/server/controllers/source.py b/subiquity/server/controllers/source.py index 22480924..3150b31d 100644 --- a/subiquity/server/controllers/source.py +++ b/subiquity/server/controllers/source.py @@ -29,6 +29,8 @@ from subiquity.common.types import SourceSelection, SourceSelectionAndSetting from subiquity.server.controller import SubiquityController from subiquity.server.types import InstallerChannels +SOURCES_DEFAULT_PATH = "/cdrom/casper/install-sources.yaml" + log = logging.getLogger("subiquity.server.controllers.source") @@ -77,16 +79,22 @@ class SourceController(SubiquityController): super().__init__(app) self._handler = None self.source_path: Optional[str] = None - self.ai_source_id: Optional[str] = None self._configured: bool = False + path = SOURCES_DEFAULT_PATH + if self.app.opts.source_catalog is not None: + path = self.app.opts.source_catalog + if os.path.exists(path): + with open(path) as fp: + self.model.load_from_file(fp) + def make_autoinstall(self): return { "search_drivers": self.model.search_drivers, "id": self.model.current.id, } - def load_autoinstall_data(self, data: Any) -> None: + def load_autoinstall_data(self, data: Optional[dict[str, Any]]) -> None: if data is None: data = {} @@ -98,22 +106,11 @@ class SourceController(SubiquityController): "search_drivers", SEARCH_DRIVERS_AUTOINSTALL_DEFAULT ) - # At this point, the model has not yet loaded the sources from the - # catalog. So we store the ID and lean on self.start to select the - # current source accordingly. - self.ai_source_id = data.get("id") + # Assign the current source if hinted by autoinstall. + if id := data.get("id"): + self.model.current = self.model.get_matching_source(id) def start(self): - path = "/cdrom/casper/install-sources.yaml" - if self.app.opts.source_catalog is not None: - path = self.app.opts.source_catalog - if not os.path.exists(path): - return - with open(path) as fp: - self.model.load_from_file(fp) - # Assign the current source if hinted by autoinstall. - if self.ai_source_id is not None: - self.model.current = self.model.get_matching_source(self.ai_source_id) self.app.hub.subscribe( (InstallerChannels.CONFIGURED, "locale"), self._set_locale ) diff --git a/subiquity/server/controllers/tests/test_identity.py b/subiquity/server/controllers/tests/test_identity.py index 8f72071f..2b4870ed 100644 --- a/subiquity/server/controllers/tests/test_identity.py +++ b/subiquity/server/controllers/tests/test_identity.py @@ -19,6 +19,7 @@ from jsonschema.validators import validator_for from subiquity.server.autoinstall import AutoinstallError from subiquity.server.controllers.filesystem import FilesystemController from subiquity.server.controllers.identity import IdentityController +from subiquity.server.controllers.source import SourceController from subiquitycore.tests import SubiTestCase from subiquitycore.tests.mocks import make_app from subiquitycore.tests.parameterized import parameterized @@ -43,6 +44,8 @@ class TestControllerUserCreationFlows(SubiTestCase): self.app.opts.bootloader = False self.app.controllers.Filesystem = FilesystemController(self.app) self.ic = IdentityController(self.app) + self.app.opts.source_catalog = "examples/sources/install.yaml" + self.app.controllers.Source = SourceController(self.app) self.ic.model.user = None # Test cases for 4a1. Copied for 4a2 but all cases should be valid for desktop. diff --git a/subiquity/server/controllers/tests/test_source.py b/subiquity/server/controllers/tests/test_source.py index 9fd97116..1e1c8fbe 100644 --- a/subiquity/server/controllers/tests/test_source.py +++ b/subiquity/server/controllers/tests/test_source.py @@ -17,8 +17,14 @@ import unittest from subiquity.common.serialize import Serializer from subiquity.models.source import CatalogEntry +from subiquity.models.subiquity import SubiquityModel from subiquity.models.tests.test_source import make_entry as make_raw_entry -from subiquity.server.controllers.source import convert_source +from subiquity.server.controllers.source import SourceController, convert_source +from subiquity.server.server import INSTALL_MODEL_NAMES, POSTINSTALL_MODEL_NAMES +from subiquitycore.pubsub import MessageHub +from subiquitycore.tests import SubiTestCase +from subiquitycore.tests.mocks import make_app +from subiquitycore.tests.parameterized import parameterized def make_entry(**kw): @@ -44,3 +50,45 @@ class TestSubiquityModel(unittest.TestCase): self.assertEqual(convert_source(entry, "fr").name, "French") self.assertEqual(convert_source(entry, "fr_CA").name, "French Canadian") self.assertEqual(convert_source(entry, "fr_BE").name, "French") + + +class TestSourceController(SubiTestCase): + def setUp(self): + self.base_model = SubiquityModel( + "test", MessageHub(), INSTALL_MODEL_NAMES, POSTINSTALL_MODEL_NAMES + ) + self.app = make_app(model=self.base_model) + self.app.opts.source_catalog = "examples/sources/install.yaml" + self.controller = SourceController(self.app) + + def _set_source_catalog(self, path): + self.app.opts.source_catalog = path + self.controller = SourceController(self.app) + + @parameterized.expand( + # (Sources list, is_desktop) + ( + ("examples/sources/desktop.yaml", "desktop"), + ("examples/sources/install.yaml", "server"), + ) + ) + def test_install_source_detection__defaults(self, catalog, expected): + """Test source detection with defaults.""" + + self._set_source_catalog(catalog) + + variant = self.controller.model.current.variant + self.assertEqual(variant, expected) + + @parameterized.expand( + # (Sources list, ai_data, expected) + ( + ("examples/sources/mixed.yaml", {"id": "ubuntu-desktop"}, "desktop"), + ("examples/sources/mixed.yaml", {"id": "ubuntu-server"}, "server"), + ) + ) + def test_install_source_detection__autoinstall(self, catalog, ai_data, expected): + """Test source detection with autoinstall.""" + self._set_source_catalog(catalog) + self.controller.load_autoinstall_data(ai_data) + self.assertEqual(self.controller.model.current.variant, expected)