diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index abafd94976..b268ace470 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest needs: pre env: - PYTEST_REQPASS: 448 + PYTEST_REQPASS: 453 # limit potential endless looks like we had with build-containers timeout-minutes: 20 strategy: diff --git a/src/molecule/data/molecule.json b/src/molecule/data/molecule.json index 5dbe465ade..5dcdf2bc47 100644 --- a/src/molecule/data/molecule.json +++ b/src/molecule/data/molecule.json @@ -79,22 +79,37 @@ "type": "string" }, "name": { - "enum": [ - "azure", - "ec2", - "delegated", - "docker", - "containers", - "openstack", - "podman", - "vagrant", - "digitalocean", - "gce", - "libvirt", - "lxd" + "anyOf": [ + { + "enum": [ + "azure", + "ec2", + "delegated", + "docker", + "containers", + "openstack", + "podman", + "vagrant", + "digitalocean", + "gce", + "libvirt", + "lxd" + ] + }, + { + "pattern": "^molecule[_\\-][a-zA-Z0-9:_.\\-]+$", + "type": "string" + }, + { + "pattern": "^custom[_\\-][a-zA-Z0-9:_.\\-]+$", + "type": "string" + } ], "title": "Name", - "type": "string" + "type": "string", + "messages": { + "anyOf": "is not one of ['azure', 'ec2', 'delegated', 'docker', 'containers', 'openstack', 'podman', 'vagrant', 'digitalocean', 'gce', 'libvirt', 'lxd', 'molecule-*', 'molecule_*', 'custom-*', 'custom_*']" + } }, "options": { "$ref": "#/$defs/MoleculeDriverOptionsModel" diff --git a/src/molecule/model/schema_v3.py b/src/molecule/model/schema_v3.py index 6f7944c8e9..20e45fe138 100644 --- a/src/molecule/model/schema_v3.py +++ b/src/molecule/model/schema_v3.py @@ -38,6 +38,14 @@ def validate(c): try: jsonschema_validate(c, schema) except ValidationError as exc: - result.append(exc.message) + # handle validation error for driver name + if exc.json_path == "$.driver.name" and exc.message.endswith( + ("is not of type 'string'", "is not valid under any of the given schemas") + ): + wrong_driver_name = str(exc.message.split()[0]) + driver_name_err_msg = exc.schema["messages"]["anyOf"] + result.append(" ".join((wrong_driver_name, driver_name_err_msg))) + else: + result.append(exc.message) return result diff --git a/src/molecule/test/unit/model/v2/test_driver_section.py b/src/molecule/test/unit/model/v2/test_driver_section.py index b653fe3b56..5229b8b21b 100644 --- a/src/molecule/test/unit/model/v2/test_driver_section.py +++ b/src/molecule/test/unit/model/v2/test_driver_section.py @@ -50,15 +50,33 @@ def _model_driver_errors_section_data(): } +@pytest.fixture +def _model_driver_errors_section_data_no_prefix(): + return { + "driver": { + "name": "random_name", + } + } + + @pytest.mark.parametrize( - "_config", ["_model_driver_errors_section_data"], indirect=True + "_config", + [ + "_model_driver_errors_section_data", + "_model_driver_errors_section_data_no_prefix", + ], + indirect=True, ) def test_driver_has_errors(_config): - x = [ - "0 is not one of ['azure', 'ec2', 'delegated', 'docker', 'containers', 'openstack', 'podman', 'vagrant', 'digitalocean', 'gce', 'libvirt', 'lxd']" - ] + base_error_msg = "is not one of ['azure', 'ec2', 'delegated', 'docker', 'containers', 'openstack', 'podman', 'vagrant', 'digitalocean', 'gce', 'libvirt', 'lxd', 'molecule-*', 'molecule_*', 'custom-*', 'custom_*']" + + driver_name = str(_config["driver"]["name"]) + if type(_config["driver"]["name"]) is str: + # add single quotes for string + driver_name = f"'{driver_name}'" - assert x == schema_v3.validate(_config) + error_msg = [" ".join((driver_name, base_error_msg))] + assert error_msg == schema_v3.validate(_config) @pytest.fixture @@ -78,11 +96,35 @@ def _model_driver_allows_delegated_section_data(): return {"driver": {"name": "delegated"}} +@pytest.fixture +def _model_driver_allows_molecule_section_data1(): + return {"driver": {"name": "molecule-test_driver.name"}} + + +@pytest.fixture +def _model_driver_allows_molecule_section_data2(): + return {"driver": {"name": "molecule_test_driver.name"}} + + +@pytest.fixture +def _model_driver_allows_custom_section_data1(): + return {"driver": {"name": "custom-test_driver.name"}} + + +@pytest.fixture +def _model_driver_allows_custom_section_data2(): + return {"driver": {"name": "custom_test_driver.name"}} + + ### @pytest.mark.parametrize( "_config", [ ("_model_driver_allows_delegated_section_data"), + ("_model_driver_allows_molecule_section_data1"), + ("_model_driver_allows_molecule_section_data2"), + ("_model_driver_allows_custom_section_data2"), + ("_model_driver_allows_custom_section_data1"), ], indirect=True, )