autoinstall: unittests to validate autoinstall schema

Provided autoinstall data is already validated against a specific
schema by the relevant controller, but these schemas themselves
are never validated against a meta schema to guarantee they are
valid JSON schemas. This patch adds unit tests for each controller,
as well as SubiquityServer, to validate their autoinstall schema
against the latest JSON meta schema draft (that is supported in
jsonschema). A particular draft validator can be used instead by
specifying meta schema in the schema definition.
This commit is contained in:
Chris Peterson 2024-01-24 15:47:24 -08:00
parent 20759840b9
commit f6a7819ef9
23 changed files with 532 additions and 0 deletions

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.cmdlist import CmdListController
from subiquitycore.tests import SubiTestCase
class TestCmdListController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
CmdListController.autoinstall_schema
)
JsonValidator.check_schema(CmdListController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.codecs import CodecsController
from subiquitycore.tests import SubiTestCase
class TestCodecsController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
CodecsController.autoinstall_schema
)
JsonValidator.check_schema(CodecsController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.debconf import DebconfController
from subiquitycore.tests import SubiTestCase
class TestDebconfController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
DebconfController.autoinstall_schema
)
JsonValidator.check_schema(DebconfController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.drivers import DriversController
from subiquitycore.tests import SubiTestCase
class TestDriversController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
DriversController.autoinstall_schema
)
JsonValidator.check_schema(DriversController.autoinstall_schema)

View File

@ -18,7 +18,9 @@ import subprocess
import uuid
from unittest import IsolatedAsyncioTestCase, mock
import jsonschema
from curtin.commands.extract import TrivialSourceHandler
from jsonschema.validators import validator_for
from subiquity.common.filesystem import gaps, labels
from subiquity.common.filesystem.actions import DeviceAction
@ -399,6 +401,15 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase):
self.assertEqual(len(self.fsc._variation_info), 1)
self.assertEqual(self.fsc._variation_info["default"].name, "default")
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
FilesystemController.autoinstall_schema
)
JsonValidator.check_schema(FilesystemController.autoinstall_schema)
class TestGuided(IsolatedAsyncioTestCase):
boot_expectations = [

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.identity import IdentityController
from subiquitycore.tests import SubiTestCase
class TestIdentityController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
IdentityController.autoinstall_schema
)
JsonValidator.check_schema(IdentityController.autoinstall_schema)

View File

@ -17,6 +17,9 @@ import os
import unittest
from unittest.mock import Mock, patch
import jsonschema
from jsonschema.validators import validator_for
from subiquity.common.types import KeyboardSetting
from subiquity.models.keyboard import KeyboardModel
from subiquity.server.controllers.keyboard import KeyboardController
@ -29,6 +32,16 @@ class opts:
dry_run = True
class TestKeyboardController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
KeyboardController.autoinstall_schema
)
JsonValidator.check_schema(KeyboardController.autoinstall_schema)
class TestSubiquityModel(SubiTestCase):
async def test_write_config(self):
os.environ["SUBIQUITY_REPLAY_TIMESCALE"] = "100"

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.locale import LocaleController
from subiquitycore.tests import SubiTestCase
class TestLocaleController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
LocaleController.autoinstall_schema
)
JsonValidator.check_schema(LocaleController.autoinstall_schema)

View File

@ -19,6 +19,7 @@ import unittest
from unittest import mock
import jsonschema
from jsonschema.validators import validator_for
from subiquity.common.types import MirrorSelectionFallback
from subiquity.models.mirror import MirrorModel
@ -264,3 +265,12 @@ class TestMirrorController(unittest.IsolatedAsyncioTestCase):
mock_fallback.assert_not_called()
await controller.run_mirror_selection_or_fallback(context=None)
mock_fallback.assert_called_once()
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
MirrorController.autoinstall_schema
)
JsonValidator.check_schema(MirrorController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.network import NetworkController
from subiquitycore.tests import SubiTestCase
class TestNetworkController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
NetworkController.autoinstall_schema
)
JsonValidator.check_schema(NetworkController.autoinstall_schema)

View File

@ -16,6 +16,9 @@
import subprocess
from unittest.mock import Mock, patch
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.oem import OEMController
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.mocks import make_app
@ -110,3 +113,12 @@ Ubuntu-Oem-Kernel-Flavour: oem
"oem-sutton-balint-meta", context=None, overlay=Mock()
)
)
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
OEMController.autoinstall_schema
)
JsonValidator.check_schema(OEMController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.package import PackageController
from subiquitycore.tests import SubiTestCase
class TestPackageController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
PackageController.autoinstall_schema
)
JsonValidator.check_schema(PackageController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.proxy import ProxyController
from subiquitycore.tests import SubiTestCase
class TestProxyController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
ProxyController.autoinstall_schema
)
JsonValidator.check_schema(ProxyController.autoinstall_schema)

View File

@ -15,6 +15,9 @@
from unittest import mock
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server import snapdapi
from subiquity.server.controllers import refresh as refresh_mod
from subiquity.server.controllers.refresh import RefreshController, SnapChannelSource
@ -99,3 +102,12 @@ class TestRefreshController(SubiTestCase):
await self.rc.configure_snapd(context=self.rc.context)
paw.assert_not_called()
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
RefreshController.autoinstall_schema
)
JsonValidator.check_schema(RefreshController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.reporting import ReportingController
from subiquitycore.tests import SubiTestCase
class TestReportingController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
ReportingController.autoinstall_schema
)
JsonValidator.check_schema(ReportingController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.shutdown import ShutdownController
from subiquitycore.tests import SubiTestCase
class TestShutdownController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
ShutdownController.autoinstall_schema
)
JsonValidator.check_schema(ShutdownController.autoinstall_schema)

View File

@ -16,13 +16,17 @@
import unittest
from unittest.mock import AsyncMock
import jsonschema
import requests
from jsonschema.validators import validator_for
from subiquity.models.snaplist import SnapListModel
from subiquity.server.controllers.snaplist import (
SnapdSnapInfoLoader,
SnapListController,
SnapListFetchError,
)
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.mocks import make_app
@ -56,3 +60,14 @@ class TestSnapdSnapInfoLoader(unittest.IsolatedAsyncioTestCase):
await self.loader.get_snap_list_task()
self.assertTrue(self.loader.fetch_list_completed())
self.assertFalse(self.loader.fetch_list_failed())
class TestSnapListController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
SnapListController.autoinstall_schema
)
JsonValidator.check_schema(SnapListController.autoinstall_schema)

View File

@ -16,6 +16,9 @@
import unittest
from unittest import mock
import jsonschema
from jsonschema.validators import validator_for
from subiquity.common.types import SSHFetchIdStatus, SSHIdentity
from subiquity.server.controllers.ssh import (
SSHController,
@ -98,3 +101,12 @@ class TestSSHController(unittest.IsolatedAsyncioTestCase):
self.assertEqual(response.status, SSHFetchIdStatus.FINGERPRINT_ERROR)
self.assertEqual(response.error, stderr)
self.assertIsNone(response.identities)
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
SSHController.autoinstall_schema
)
JsonValidator.check_schema(SSHController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.timezone import TimeZoneController
from subiquitycore.tests import SubiTestCase
class TestTimeZoneController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
TimeZoneController.autoinstall_schema
)
JsonValidator.check_schema(TimeZoneController.autoinstall_schema)

View File

@ -15,6 +15,9 @@
import unittest
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.ubuntu_pro import UbuntuProController
from subiquity.server.dryrun import DRConfig
from subiquitycore.tests.mocks import make_app
@ -33,3 +36,12 @@ class TestUbuntuProController(unittest.TestCase):
def test_deserialize(self):
self.controller.deserialize("1A2B3C4D")
self.assertEqual(self.controller.model.token, "1A2B3C4D")
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
UbuntuProController.autoinstall_schema
)
JsonValidator.check_schema(UbuntuProController.autoinstall_schema)

View File

@ -0,0 +1,31 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jsonschema
from jsonschema.validators import validator_for
from subiquity.server.controllers.updates import UpdatesController
from subiquitycore.tests import SubiTestCase
class TestUpdatesController(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
UpdatesController.autoinstall_schema
)
JsonValidator.check_schema(UpdatesController.autoinstall_schema)

View File

@ -15,7 +15,9 @@
import unittest
import jsonschema
from cloudinit.config.schema import SchemaValidationError
from jsonschema.validators import validator_for
from subiquity.server.controllers.userdata import UserdataController
from subiquitycore.tests.mocks import make_app
@ -58,3 +60,12 @@ class TestUserdataController(unittest.TestCase):
validate.assert_called_with(
data=invalid_schema, data_source="autoinstall.user-data"
)
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
UserdataController.autoinstall_schema
)
JsonValidator.check_schema(UserdataController.autoinstall_schema)

View File

@ -17,6 +17,9 @@ import os
import shlex
from unittest.mock import Mock, patch
import jsonschema
from jsonschema.validators import validator_for
from subiquity.common.types import PasswordKind
from subiquity.server.server import (
MetaController,
@ -141,6 +144,24 @@ early-commands: ["{cmd}"]
self.assertEqual(after_early, self.server.autoinstall_config)
class TestAutoinstallValidation(SubiTestCase):
async def asyncSetUp(self):
opts = Mock()
opts.dry_run = True
opts.output_base = self.tmp_dir()
opts.machine_config = "examples/machines/simple.json"
self.server = SubiquityServer(opts, None)
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""
JsonValidator: jsonschema.protocols.Validator = validator_for(
SubiquityServer.base_schema
)
JsonValidator.check_schema(SubiquityServer.base_schema)
class TestMetaController(SubiTestCase):
async def test_interactive_sections_not_present(self):
mc = MetaController(make_app())