def __init__(self, project: project.Project) -> None: self.build_snaps: Set[str] = set() self.project = project # raw_snapcraft_yaml is read only, create a new copy snapcraft_yaml = apply_extensions(project.info.get_raw_snapcraft()) self.validator = Validator(snapcraft_yaml) self.validator.validate() snapcraft_yaml = self._expand_filesets(snapcraft_yaml) self.data = self._expand_env(snapcraft_yaml) self.data["architectures"] = _process_architectures( self.data.get("architectures"), project.deb_arch) self._ensure_no_duplicate_app_aliases() self._global_grammar_processor = grammar_processing.GlobalGrammarProcessor( properties=self.data, arch=project.host_deb_arch, target_arch=project.target_arch, ) # XXX: Resetting snap_meta due to above mangling of data. # Convergence to operating on snap_meta will remove this requirement... project._snap_meta = Snap.from_dict(self.data) self.parts = PartsConfig(parts=self.data, project=project, validator=self.validator)
def test_invalid_yaml_invalid_username(data): data["system-usernames"] = {"snap_user": "******"} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = "The 'system-usernames' property does not match the required schema: 'snap_user' is not a valid system-username." assert expected_message in str(error.value)
def test_invalid_yaml_invalid_long_scope(data): data["system-usernames"] = {"snap_daemon": {"scope": "invalid-scope"}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = "The 'system-usernames/snap_daemon' property does not match the required schema: {'scope': 'invalid-scope'} is not valid under any of the given schemas" assert expected_message in str(error.value)
def test_invalid(self, data, packages, message_contains): data["package-repositories"] = packages with pytest.raises(snapcraft_legacy.yaml_utils.errors. YamlValidationError) as error: Validator(data).validate() assert message_contains in str(error.value)
def test(self, data, architectures, message): data["architectures"] = architectures with pytest.raises(snapcraft_legacy.yaml_utils.errors. YamlValidationError) as error: Validator(data).validate() assert message in str(error.value)
def test_required_properties(data, key): del data[key] with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() assert f"{key!r} is a required property" in str(error.value)
def test_type_base_and_base(data): data["type"] = "base" with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() assert _BASE_TYPE_MSG in str(error.value)
def test_invalid_adapter(data, adapter): data["apps"] = {"foo": {"command": "foo", "adapter": adapter}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = "The 'apps/foo/adapter' property does not match" assert expected_message in str(error.value)
def test_invalid_command_chain(data, command_chain): data["apps"] = {"foo": {"command": "foo", "command-chain": command_chain}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = "The 'apps/foo/command-chain" assert expected_message in str(error.value)
def test_invalid_title(data, title, error_template): data["title"] = title with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() assert _EXPECTED_ERROR_TEMPLATE[error_template].format(title) in str( error.value)
def test_valid_modes(data, mode): data["apps"] = { "service1": { "command": "binary1", "daemon": "simple", "stop-mode": mode } } Validator(data).validate()
def test_invalid_metadata_links(data, contact, donation, issues, source_code, website): data["contact"] = contact data["donation"] = donation data["issues"] = issues data["source-code"] = source_code data["website"] = website with pytest.raises(snapcraft_legacy.yaml_utils.errors.YamlValidationError): Validator(data).validate()
def test(self, data, name, err): data["name"] = name with pytest.raises(snapcraft_legacy.yaml_utils.errors. YamlValidationError) as error: Validator(data).validate() assert str(error.value).endswith( f"The 'name' property does not match the required schema: {name!r} is {err}" )
def test_daemon_dependency(data, option, value): data["apps"] = {"service1": {"command": "binary1", option: value}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() assert str(error.value).endswith( "The 'apps/service1' property does not match the required schema: " f"'daemon' is a dependency of {option!r}")
def test_invalid_grade(data, grade): data["grade"] = grade with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ("The 'grade' property does not match the required " f"schema: {grade!r} is not one of ['stable', 'devel']") assert expected_message in str(error.value)
def test_invalid_compression(data, compression): data["compression"] = compression with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'compression' property does not match the required " f"schema: {compression!r} is not one of ['lzo', 'xz']") assert expected_message in str(error.value)
def test_invalid_description(data, desc): data["description"] = desc with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'description' property does not match the required " f"schema: {desc!r} is not a valid description string") assert expected_message in str(error.value)
def test_invalid_epoch(data, epoch): data["epoch"] = epoch with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( f"{epoch!r} is not a 'epoch' (epochs are positive integers " "followed by an optional asterisk)") assert expected_message in str(error.value)
def test_invalid_license(data): data["license"] = 1234 with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'license' property does not match the required schema: " "1234 is not of type 'string'") assert expected_message in str(error.value)
def test_invalid_confinement(data, confinement): data["confinement"] = confinement with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'confinement' property does not match the required " f"schema: {confinement!r} is not one of ['classic', 'devmode', " "'strict']") assert expected_message in str(error.value)
def test_invalid_version_length(data): data["version"] = "this.is.a.really.too.long.version" with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'version' property does not match the required " "schema: 'this.is.a.really.too.long.version' is too long " "(maximum length is 32)") assert expected_message in str(error.value)
def test_invalid_part_names(data, name): data["parts"] = {name: {"plugin": "nil"}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( f"The 'parts' property does not match the required schema: {name!r} is " "not a valid part name. Part names consist of lower-case " "alphanumeric characters, hyphens and plus signs. " "As a special case, 'plugins' is also not a valid part name.") assert str(error.value).endswith(expected_message)
def test_invalid_hook_names(data, name): data["hooks"] = {name: {"plugs": ["network"]}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( f"The 'hooks' property does not match the required schema: {name!r} is " "not a valid hook name. Hook names consist of lower-case " "alphanumeric characters and hyphens. They cannot start or end " "with a hyphen.") assert expected_message in str(error.value)
def test_invalid_app_names(data, name): data["apps"] = {name: {"command": "1"}} with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( f"The 'apps' property does not match the required schema: {name!r} is " "not a valid app name. App names consist of upper- and lower-case " "alphanumeric characters and hyphens. They cannot start or end " "with a hyphen.") assert expected_message in str(error.value)
def test_apps_required_properties(self): self.data["apps"] = {"service1": {}} raised = self.assertRaises( snapcraft_legacy.yaml_utils.errors.YamlValidationError, Validator(self.data).validate, ) expected_message = ("The 'apps/service1' property does not match the " "required schema: 'command' is a required " "property") self.assertThat(raised.message, Equals(expected_message), message=self.data)
def test_summary_too_long(self): self.data["summary"] = "a" * 80 raised = self.assertRaises( snapcraft_legacy.yaml_utils.errors.YamlValidationError, Validator(self.data).validate, ) expected_message = ( "The 'summary' property does not match the required schema: " "'{}' is too long (maximum length is 78)").format( self.data["summary"]) self.assertThat(raised.message, Equals(expected_message), message=self.data)
def test_invalid_version_type(data): data["version"] = 0.1 with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ("The 'version' property does not match the required " "schema: snap versions need to be strings. They must " "also be wrapped in quotes when the value will be " "interpreted by the YAML parser as a non-string. " "Examples: '1', '1.2', '1.2.3', git (will be replaced " "by a git describe based version string).") assert expected_message in str(error.value)
def test_missing_required_property_and_missing_adopt_info(self): del self.data["summary"] del self.data["adopt-info"] raised = self.assertRaises( snapcraft_legacy.yaml_utils.errors.YamlValidationError, Validator(self.data).validate, ) expected_message = ( "'adopt-info' is a required property or 'summary' is a required property" ) self.assertThat(raised.message, Equals(expected_message), message=self.data)
def test_invalid_version(data, version): data["version"] = version with pytest.raises( snapcraft_legacy.yaml_utils.errors.YamlValidationError) as error: Validator(data).validate() expected_message = ( "The 'version' property does not match the required " f"schema: {version!r} is not a valid snap version string. Snap versions " "consist of upper- and lower-case alphanumeric characters, " "as well as periods, colons, plus signs, tildes, and " "hyphens. They cannot begin with a period, colon, plus " "sign, tilde, or hyphen. They cannot end with a period, " "colon, or hyphen.") assert expected_message in str(error.value)
def test_valid_metadata_links(data, contact, donation, issues, source_code, website): if all(ml is None for ml in [contact, donation, issues, source_code, website]): pytest.skip("All metadata links are unset") if contact is not None: data["contact"] = contact if donation is not None: data["donation"] = donation if issues is not None: data["issues"] = issues if source_code is not None: data["source-code"] = source_code if website is not None: data["website"] = website Validator(data).validate()