cleanup(tests): Major rework of inventory unit tests

Rework the inventory unit tests by splitting up
tests/unit/plugins/inventory/test_kubevirt.py into multiple files,
by trying to simplify the test code and making it more robust and by
using appropriate fixtures. This also adds new tests or test cases to
improve code coverage. Tests that work from the black box perspective
are now located in a subdirectory.

Signed-off-by: Felix Matouschek <fmatouschek@redhat.com>
This commit is contained in:
Felix Matouschek
2024-06-27 13:34:07 +02:00
parent a94eda613f
commit be65833724
18 changed files with 1927 additions and 1087 deletions

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
merge_dicts,
)
BASE_VMI = {
"metadata": {
"name": "testvmi",
"namespace": "default",
},
"status": {
"interfaces": [{"ipAddress": "10.10.10.10"}],
},
}
WINDOWS_VMI_1 = merge_dicts(
BASE_VMI,
{
"status": {
"guestOSInfo": {"id": "mswindows"},
}
},
)
WINDOWS_VMI_2 = merge_dicts(
BASE_VMI,
{
"metadata": {
"annotations": {"kubevirt.io/cluster-preference-name": "windows.2k22"}
},
},
)
WINDOWS_VMI_3 = merge_dicts(
BASE_VMI,
{
"metadata": {"annotations": {"kubevirt.io/preference-name": "windows.2k22"}},
},
)
WINDOWS_VMI_4 = merge_dicts(
BASE_VMI,
{
"metadata": {"annotations": {"vm.kubevirt.io/os": "windows2k22"}},
},
)
@pytest.mark.parametrize(
"client,vmi,expected",
[
({"vmis": [BASE_VMI]}, BASE_VMI, False),
({"vmis": [WINDOWS_VMI_1]}, WINDOWS_VMI_1, True),
({"vmis": [WINDOWS_VMI_2]}, WINDOWS_VMI_2, True),
({"vmis": [WINDOWS_VMI_3]}, WINDOWS_VMI_3, True),
({"vmis": [WINDOWS_VMI_4]}, WINDOWS_VMI_4, True),
],
indirect=["client"],
)
def test_ansible_connection_winrm(inventory, hosts, client, vmi, expected):
inventory.populate_inventory_from_namespace(
client, "", DEFAULT_NAMESPACE, InventoryOptions()
)
host = f"{DEFAULT_NAMESPACE}-{vmi['metadata']['name']}"
if expected:
assert hosts[host]["ansible_connection"] == "winrm"
else:
assert "ansible_connection" not in hosts[host]

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
)
VMI = {
"metadata": {
"name": "testvmi",
"namespace": "default",
},
"status": {
"interfaces": [{"ipAddress": "10.10.10.10"}],
"migrationMethod": "BlockMigration",
"nodeName": "test-node",
"guestOSInfo": {
"id": "fedora",
"versionId": "40",
},
},
}
@pytest.mark.parametrize(
"client",
[{"vmis": [VMI]}],
indirect=["client"],
)
def test_set_composable_vars(
inventory,
groups,
hosts,
client,
):
inventory._options = {
"compose": {"set_from_another_var": "vmi_node_name"},
"groups": {"block_migratable_vmis": "vmi_migration_method == 'BlockMigration'"},
"keyed_groups": [{"prefix": "fedora", "key": "vmi_guest_os_info.versionId"}],
"strict": True,
}
inventory.populate_inventory_from_namespace(
client, "", DEFAULT_NAMESPACE, InventoryOptions()
)
host = f"{DEFAULT_NAMESPACE}-testvmi"
assert hosts[host]["set_from_another_var"] == "test-node"
assert "block_migratable_vmis" in groups
assert host in groups["block_migratable_vmis"]["children"]
assert "fedora_40" in groups
assert host in groups["fedora_40"]["children"]

View File

@@ -0,0 +1,151 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from addict import Dict
from ansible.template import Templar
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryModule,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_BASE_DOMAIN,
DEFAULT_NAMESPACE,
)
@pytest.fixture(scope="function")
def inventory(mocker):
inventory = InventoryModule()
inventory.inventory = mocker.Mock()
inventory.templar = Templar(loader=None)
inventory._options = {
"compose": {},
"groups": {},
"keyed_groups": [],
"strict": True,
}
return inventory
@pytest.fixture(scope="function")
def inventory_data(mocker, inventory):
groups = {}
hosts = {}
def add_group(group):
if group not in groups:
groups[group] = {"children": [], "vars": {}}
return group
def add_child(group, name):
if name not in groups[group]["children"]:
groups[group]["children"].append(name)
def add_host(host, group=None):
if host not in hosts:
hosts[host] = {}
if group is not None:
add_child(group, host)
def get_host(hostname):
host = mocker.Mock()
host.get_vars = mocker.Mock(return_value=hosts[hostname])
return host
def set_variable(name, key, value):
if name in groups:
groups[name]["vars"][key] = value
else:
hosts[name][key] = value
mocker.patch.object(inventory.inventory, "add_group", add_group)
mocker.patch.object(inventory.inventory, "add_child", add_child)
mocker.patch.object(inventory.inventory, "add_host", add_host)
mocker.patch.object(inventory.inventory, "get_host", get_host)
mocker.patch.object(inventory.inventory, "set_variable", set_variable)
return groups, hosts
@pytest.fixture(scope="function")
def groups(inventory_data):
return inventory_data[0]
@pytest.fixture(scope="function")
def hosts(inventory_data):
return inventory_data[1]
@pytest.fixture(scope="function")
def client(mocker, request):
param = {}
if hasattr(request, "param"):
param = request.param
namespaces = mocker.Mock()
if "namespaces" in param:
items = param["namespaces"]
else:
items = [{"metadata": {"name": DEFAULT_NAMESPACE}}]
namespaces.items = [Dict(item) for item in items]
vms = mocker.Mock()
vms.items = [Dict(item) for item in param.get("vms", [])]
vmis = mocker.Mock()
vmis.items = [Dict(item) for item in param.get("vmis", [])]
services = mocker.Mock()
services.items = [Dict(item) for item in param.get("services", [])]
dns = mocker.Mock()
if "base_domain" in param:
base_domain = param["base_domain"]
else:
base_domain = DEFAULT_BASE_DOMAIN
dns_obj = Dict({"spec": {"baseDomain": base_domain}})
dns.items = [dns_obj]
namespace_client = mocker.Mock()
namespace_client.get = mocker.Mock(return_value=namespaces)
vm_client = mocker.Mock()
vm_client.get = mocker.Mock(return_value=vms)
vmi_client = mocker.Mock()
vmi_client.get = mocker.Mock(return_value=vmis)
service_client = mocker.Mock()
service_client.get = mocker.Mock(return_value=services)
def dns_client_get(**kwargs):
if "name" in kwargs:
return dns_obj
return dns
dns_client = mocker.Mock()
dns_client.get = dns_client_get
def resources_get(api_version="", kind=""):
if api_version.lower() == "v1":
if kind.lower() == "namespace":
return namespace_client
if kind.lower() == "service":
return service_client
elif api_version.lower() == "config.openshift.io/v1" and kind.lower() == "dns":
return dns_client
elif "kubevirt.io/" in api_version.lower():
if kind.lower() == "virtualmachine":
return vm_client
if kind.lower() == "virtualmachineinstance":
return vmi_client
return None
client = mocker.Mock()
client.resources.get = resources_get
return client

View File

@@ -8,6 +8,9 @@ __metaclass__ = type
from copy import deepcopy
DEFAULT_NAMESPACE = "default"
DEFAULT_BASE_DOMAIN = "example.com"
def merge_dicts(dict1, dict2):
merged = deepcopy(dict1)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from addict import Dict
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
)
@pytest.mark.parametrize(
"host_format,expected",
[
("static", "static"),
("{name}", "testvm"),
("{name}-static", "testvm-static"),
("{namespace}", "default"),
("{uid}", "f8abae7c-d792-4b9b-af95-62d322ae5bc1"),
("{name}-{namespace}", "testvm-default"),
("{name}-{namespace}-static", "testvm-default-static"),
("{name}-{uid}", "testvm-f8abae7c-d792-4b9b-af95-62d322ae5bc1"),
("{namespace}-{name}", "default-testvm"),
("{namespace}-{uid}", "default-f8abae7c-d792-4b9b-af95-62d322ae5bc1"),
("{uid}-{name}", "f8abae7c-d792-4b9b-af95-62d322ae5bc1-testvm"),
("{uid}-{namespace}", "f8abae7c-d792-4b9b-af95-62d322ae5bc1-default"),
(
"{name}-{namespace}-{uid}",
"testvm-default-f8abae7c-d792-4b9b-af95-62d322ae5bc1",
),
(
"{name}-{namespace}-{uid}-static",
"testvm-default-f8abae7c-d792-4b9b-af95-62d322ae5bc1-static",
),
(
"{name}-{uid}-{namespace}",
"testvm-f8abae7c-d792-4b9b-af95-62d322ae5bc1-default",
),
(
"{namespace}-{name}-{uid}",
"default-testvm-f8abae7c-d792-4b9b-af95-62d322ae5bc1",
),
(
"{namespace}-{uid}-{name}",
"default-f8abae7c-d792-4b9b-af95-62d322ae5bc1-testvm",
),
(
"{uid}-{namespace}-{name}",
"f8abae7c-d792-4b9b-af95-62d322ae5bc1-default-testvm",
),
(
"{uid}-{name}-{namespace}",
"f8abae7c-d792-4b9b-af95-62d322ae5bc1-testvm-default",
),
],
)
def test_add_host(inventory, groups, hosts, host_format, expected):
namespace_group = "namespace_default"
inventory.inventory.add_group(namespace_group)
inventory.add_host(
Dict(
{
"metadata": {
"name": "testvm",
"namespace": DEFAULT_NAMESPACE,
"uid": "f8abae7c-d792-4b9b-af95-62d322ae5bc1",
}
}
),
host_format,
namespace_group,
)
assert expected in hosts
assert expected in groups[namespace_group]["children"]

View File

@@ -1,119 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryModule,
)
from ansible.template import Templar
@pytest.fixture(scope="function")
def inventory_composable_vars(mocker):
inventory = InventoryModule()
inventory.templar = Templar(loader=None)
inventory._options = {
"compose": {"block_migratable_vmis": "vmi_migration_method"},
"strict": True,
"groups": {"vmi_node_groups": "cluster_name"},
"keyed_groups": [{"prefix": "fedora", "key": "vmi_guest_os_info.version"}],
}
inventory.inventory = mocker.Mock()
return inventory
@pytest.fixture(scope="function")
def host_vars(monkeypatch, inventory_composable_vars):
host_vars = {}
def set_variable(host, key, value):
if host not in host_vars:
host_vars[host] = {}
host_vars[host][key] = value
monkeypatch.setattr(
inventory_composable_vars.inventory, "set_variable", set_variable
)
return host_vars
@pytest.fixture(scope="function")
def add_group(monkeypatch, inventory_composable_vars):
groups = []
def add_group(name):
if name not in groups:
groups.append(name)
return name
monkeypatch.setattr(inventory_composable_vars.inventory, "add_group", add_group)
return groups
@pytest.fixture(scope="function")
def add_host(monkeypatch, inventory_composable_vars):
hosts = []
def add_host(name, group=None):
if name not in hosts:
hosts.append(name)
if group is not None and group not in hosts:
hosts.append(group)
monkeypatch.setattr(inventory_composable_vars.inventory, "add_host", add_host)
return hosts
@pytest.fixture(scope="function")
def add_child(monkeypatch, inventory_composable_vars):
children = {}
def add_child(group, name):
if group not in children:
children[group] = []
if name not in children[group]:
children[group].append(name)
monkeypatch.setattr(inventory_composable_vars.inventory, "add_child", add_child)
return children
@pytest.fixture(scope="module")
def vmi_host_vars():
return {
"vmi_migration_method": "BlockMigration",
"vmi_guest_os_info": {"id": "fedora", "version": "39"},
"cluster_name": {"test-cluster"},
}
def test_set_composable_vars(
inventory_composable_vars,
mocker,
host_vars,
add_group,
add_child,
add_host,
vmi_host_vars,
):
get_vars = mocker.patch.object(
inventory_composable_vars.inventory.get_host(), "get_vars"
)
get_vars.return_value = vmi_host_vars
inventory_composable_vars.set_composable_vars("testvmi")
assert {"testvmi": {"block_migratable_vmis": "BlockMigration"}} == host_vars
assert ["vmi_node_groups", "fedora_39"] == add_group
assert {"vmi_node_groups": ["testvmi"]} == add_child
assert ["testvmi", "fedora_39"] == add_host

View File

@@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
KubeVirtInventoryException,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
)
from ansible_collections.kubevirt.core.plugins.inventory import kubevirt
@pytest.mark.parametrize(
"connections,expected",
[
(
None,
[
{
"name": "default-hostname",
"namespace": DEFAULT_NAMESPACE,
"opts": InventoryOptions(),
},
],
),
(
[
{
"name": "test",
},
],
[
{
"name": "test",
"namespace": DEFAULT_NAMESPACE,
"opts": InventoryOptions(),
},
],
),
(
[
{"name": "test", "namespaces": ["test"]},
],
[
{"name": "test", "namespace": "test", "opts": InventoryOptions()},
],
),
(
[
{
"name": "test",
"namespaces": ["test"],
"use_service": True,
"create_groups": True,
"append_base_domain": True,
"base_domain": "test-domain",
},
],
[
{
"name": "test",
"namespace": "test",
"opts": InventoryOptions(
use_service=True,
create_groups=True,
append_base_domain=True,
base_domain="test-domain",
),
},
],
),
(
[
{
"name": "test",
"namespaces": ["test"],
"use_service": True,
"create_groups": True,
"append_base_domain": True,
"base_domain": "test-domain",
"network_name": "test-network",
},
],
[
{
"name": "test",
"namespace": "test",
"opts": InventoryOptions(
use_service=True,
create_groups=True,
append_base_domain=True,
base_domain="test-domain",
network_name="test-network",
),
},
],
),
(
[
{
"name": "test",
"namespaces": ["test"],
"use_service": True,
"create_groups": True,
"append_base_domain": True,
"base_domain": "test-domain",
"interface_name": "test-interface",
},
],
[
{
"name": "test",
"namespace": "test",
"opts": InventoryOptions(
use_service=True,
create_groups=True,
append_base_domain=True,
base_domain="test-domain",
network_name="test-interface",
),
},
],
),
(
[
{
"name": "test",
},
{"name": "test", "namespaces": ["test"]},
],
[
{
"name": "test",
"namespace": DEFAULT_NAMESPACE,
"opts": InventoryOptions(),
},
{"name": "test", "namespace": "test", "opts": InventoryOptions()},
],
),
],
)
def test_fetch_objects(mocker, inventory, connections, expected):
mocker.patch.object(kubevirt, "get_api_client")
mocker.patch.object(
inventory, "get_default_host_name", return_value="default-hostname"
)
cluster_domain = "test.com"
mocker.patch.object(inventory, "get_cluster_domain", return_value=cluster_domain)
for e in expected:
e["opts"].base_domain = e["opts"].base_domain or cluster_domain
get_available_namespaces = mocker.patch.object(
inventory, "get_available_namespaces", return_value=[DEFAULT_NAMESPACE]
)
populate_inventory_from_namespace = mocker.patch.object(
inventory, "populate_inventory_from_namespace"
)
inventory.fetch_objects(connections)
get_available_namespaces.assert_has_calls(
[mocker.call(mocker.ANY) for c in connections or [{}] if "namespaces" not in c]
)
populate_inventory_from_namespace.assert_has_calls(
[
mocker.call(mocker.ANY, e["name"], e["namespace"], e["opts"])
for e in expected
]
)
@pytest.mark.parametrize(
"connections,expected",
[
("test", "Expecting connections to be a list."),
(["test", "test"], "Expecting connection to be a dictionary."),
],
)
def test_fetch_objects_exceptions(inventory, connections, expected):
with pytest.raises(KubeVirtInventoryException, match=expected):
inventory.fetch_objects(connections)

View File

@@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from json import dumps
import pytest
from kubernetes.dynamic.exceptions import DynamicApiError
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryModule,
)
@pytest.fixture(scope="function")
def body_error(mocker):
error = DynamicApiError(e=mocker.Mock())
error.headers = None
error.body = "This is a test error"
return error
@pytest.fixture(scope="function")
def message_error(mocker):
error = DynamicApiError(e=mocker.Mock())
error.headers = {"Content-Type": "application/json"}
error.body = dumps({"message": "This is a test error"}).encode("utf-8")
return error
@pytest.fixture(scope="function")
def status_reason_error(mocker):
error = DynamicApiError(e=mocker.Mock())
error.body = None
error.status = 404
error.reason = "This is a test error"
return error
@pytest.mark.parametrize(
"exc,expected",
[
("body_error", "This is a test error"),
("message_error", "This is a test error"),
("status_reason_error", "404 Reason: This is a test error"),
],
)
def test_format_dynamic_api_exc(request, exc, expected):
assert (
InventoryModule.format_dynamic_api_exc(request.getfixturevalue(exc)) == expected
)

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
DEFAULT_BASE_DOMAIN,
)
@pytest.mark.parametrize(
"client",
[
{
"vms": [{"metadata": {"name": "testvm"}}],
"vmis": [{"metadata": {"name": "testvmi"}}],
"services": [{"metadata": {"name": "testsvc"}}],
},
],
indirect=["client"],
)
def test_get_resources(inventory, client):
assert inventory.get_resources(client, "v1", "Namespace") == [
{"metadata": {"name": DEFAULT_NAMESPACE}}
]
assert inventory.get_resources(client, "v1", "Service") == [
{"metadata": {"name": "testsvc"}}
]
assert inventory.get_resources(client, "config.openshift.io/v1", "DNS") == [
{"spec": {"baseDomain": DEFAULT_BASE_DOMAIN}}
]
assert inventory.get_resources(client, "kubevirt.io/v1", "VirtualMachine") == [
{"metadata": {"name": "testvm"}}
]
assert inventory.get_resources(
client, "kubevirt.io/v1", "VirtualMachineInstance"
) == [{"metadata": {"name": "testvmi"}}]
@pytest.mark.parametrize(
"client,expected",
[
(
{},
[DEFAULT_NAMESPACE],
),
(
{
"namespaces": [
{"metadata": {"name": DEFAULT_NAMESPACE}},
{"metadata": {"name": "test"}},
]
},
[DEFAULT_NAMESPACE, "test"],
),
],
indirect=["client"],
)
def test_get_available_namespaces(inventory, client, expected):
assert inventory.get_available_namespaces(client) == expected
@pytest.mark.parametrize(
"client",
[
{
"vms": [
{"metadata": {"name": "testvm1"}},
{"metadata": {"name": "testvm2"}},
],
},
],
indirect=["client"],
)
def test_get_vms_for_namespace(inventory, client):
assert inventory.get_vms_for_namespace(
client, DEFAULT_NAMESPACE, InventoryOptions()
) == [{"metadata": {"name": "testvm1"}}, {"metadata": {"name": "testvm2"}}]
@pytest.mark.parametrize(
"client",
[
{
"vmis": [
{"metadata": {"name": "testvmi1"}},
{"metadata": {"name": "testvmi2"}},
],
},
],
indirect=["client"],
)
def test_get_vmis_for_namespace(inventory, client):
assert inventory.get_vmis_for_namespace(
client, DEFAULT_NAMESPACE, InventoryOptions()
) == [{"metadata": {"name": "testvmi1"}}, {"metadata": {"name": "testvmi2"}}]

View File

@@ -0,0 +1,168 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
)
SVC_LB_SSH = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-lb-ssh"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 22,
"targetPort": 22,
},
],
"type": "LoadBalancer",
"selector": {"kubevirt.io/domain": "test-lb-ssh"},
},
}
SVC_NP_SSH = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-np-ssh"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 22,
"targetPort": 22,
},
],
"type": "NodePort",
"selector": {"kubevirt.io/domain": "test-np-ssh"},
},
}
@pytest.mark.parametrize(
"client",
[
{
"services": [SVC_LB_SSH, SVC_NP_SSH],
},
],
indirect=["client"],
)
def test_get_ssh_services_for_namespace(inventory, client):
assert inventory.get_ssh_services_for_namespace(client, DEFAULT_NAMESPACE) == {
"test-lb-ssh": SVC_LB_SSH,
"test-np-ssh": SVC_NP_SSH,
}
SVC_CLUSTERIP = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-clusterip"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 22,
"targetPort": 22,
},
],
"type": "ClusterIP",
"selector": {"kubevirt.io/domain": "test-clusterip"},
},
}
SVC_HTTP = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-http"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 80,
"targetPort": 80,
},
],
"type": "LoadBalancer",
"selector": {"kubevirt.io/domain": "test-http"},
},
}
SVC_NO_SPEC = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-no-spec"},
}
SVC_NO_TYPE = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-no-type"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 22,
"targetPort": 22,
},
],
"selector": {"kubevirt.io/domain": "test-no-type"},
},
}
SVC_NO_PORTS = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-no-ports"},
"spec": {
"type": "LoadBalancer",
"selector": {"kubevirt.io/domain": "test-no-ports"},
},
}
SVC_NO_SELECTOR = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {"name": "test-no-selector"},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 22,
"targetPort": 22,
},
],
"type": "LoadBalancer",
},
}
@pytest.mark.parametrize(
"client",
[
{
"services": [
SVC_HTTP,
SVC_CLUSTERIP,
SVC_NO_SPEC,
SVC_NO_TYPE,
SVC_NO_PORTS,
SVC_NO_SELECTOR,
],
},
],
indirect=["client"],
)
def test_ignore_unwanted_services(inventory, client):
assert not inventory.get_ssh_services_for_namespace(client, DEFAULT_NAMESPACE)

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
def test_inventory_options_defaults():
opts = InventoryOptions()
assert opts.api_version == "kubevirt.io/v1"
assert opts.label_selector is None
assert opts.network_name is None
assert opts.kube_secondary_dns is False
assert opts.use_service is True
assert opts.create_groups is False
assert opts.base_domain is None
assert opts.append_base_domain is False
assert opts.host_format == "{namespace}-{name}"
def test_inventory_options_override_defaults():
api_version = "test/v1"
label_selector = "test-selector"
network_name = "test-network"
kube_secondary_dns = True
use_service = False
create_groups = True
base_domain = "test-domain.com"
append_base_domain = True
host_format = "{name}-testhost"
opts = InventoryOptions(
api_version=api_version,
label_selector=label_selector,
network_name=network_name,
kube_secondary_dns=kube_secondary_dns,
use_service=use_service,
create_groups=create_groups,
base_domain=base_domain,
append_base_domain=append_base_domain,
host_format=host_format,
)
assert opts.api_version == api_version
assert opts.label_selector == label_selector
assert opts.network_name == network_name
assert opts.kube_secondary_dns == kube_secondary_dns
assert opts.use_service == use_service
assert opts.create_groups == create_groups
assert opts.base_domain == base_domain
assert opts.append_base_domain == append_base_domain
assert opts.host_format == host_format

View File

@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from addict import Dict
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
from ansible_collections.kubevirt.core.tests.unit.plugins.inventory.constants import (
DEFAULT_NAMESPACE,
)
VM1 = {
"metadata": {
"name": "testvm1",
"namespace": DEFAULT_NAMESPACE,
"uid": "940003aa-0160-4b7e-9e55-8ec3df72047f",
},
}
VM2 = {
"metadata": {
"name": "testvm2",
"namespace": DEFAULT_NAMESPACE,
"uid": "c2c68de5-b9d7-4c25-872f-462e7245b3e6",
},
}
VMI1 = {
"metadata": {
"name": "testvm1",
"namespace": DEFAULT_NAMESPACE,
"uid": "a84319a9-db31-4a36-9b66-3e387578f871",
},
"status": {
"interfaces": [{"ipAddress": "10.10.10.10"}],
},
}
VMI2 = {
"metadata": {
"name": "testvm2",
"namespace": DEFAULT_NAMESPACE,
"uid": "fd35700a-9cbe-488b-8f32-7adbe57eadc2",
},
"status": {
"interfaces": [{"ipAddress": "10.10.10.10"}],
},
}
@pytest.mark.parametrize(
"vms,vmis,expected",
[
([], [], 0),
([VM1], [], 1),
([VM1, VM2], [], 2),
([VM1], [VMI1], 1),
([VM2], [VMI2], 1),
([VM1], [VMI2], 2),
([VM2], [VMI1], 2),
([VM1], [VMI1, VMI2], 2),
([VM2], [VMI1, VMI2], 2),
([VM1, VM2], [VMI1, VMI2], 2),
([], [VMI1], 1),
([], [VMI1, VMI2], 2),
],
)
def test_populate_inventory_from_namespace(
mocker, inventory, groups, vms, vmis, expected
):
_vms = {vm["metadata"]["name"]: Dict(vm) for vm in vms}
_vmis = {vmi["metadata"]["name"]: Dict(vmi) for vmi in vmis}
opts = InventoryOptions()
def format_hostname(obj):
return opts.host_format.format(
namespace=obj.metadata.namespace,
name=obj.metadata.name,
uid=obj.metadata.uid,
)
def add_host_call(obj):
return mocker.call(
obj,
opts.host_format,
f"namespace_{DEFAULT_NAMESPACE}",
)
add_host_side_effects = []
add_host_calls = []
set_vars_from_vm_calls = []
set_vars_from_vmi_calls = []
set_composable_vars_calls = []
# For each VM add the expected calls
# Also add expected calls for VMIs for which a VM exists
for name, vm in _vms.items():
hostname = format_hostname(vm)
add_host_side_effects.append(hostname)
add_host_calls.append(add_host_call(vm))
set_vars_from_vm_calls.append(mocker.call(hostname, vm, opts))
if name in _vmis.keys():
set_vars_from_vmi_calls.append(mocker.call(hostname, _vmis[name], [], opts))
set_composable_vars_calls.append(mocker.call(hostname))
# For each VMI add the expected calls
# Do not add for VMIs for which a VM exists
for name, vmi in _vmis.items():
if name not in _vms.keys():
hostname = format_hostname(vmi)
add_host_side_effects.append(hostname)
add_host_calls.append(add_host_call(vmi))
set_vars_from_vmi_calls.append(mocker.call(hostname, vmi, [], opts))
set_composable_vars_calls.append(mocker.call(hostname))
get_vms_for_namespace = mocker.patch.object(
inventory, "get_vms_for_namespace", return_value=_vms.values()
)
get_vmis_for_namespace = mocker.patch.object(
inventory, "get_vmis_for_namespace", return_value=_vmis.values()
)
get_ssh_services_for_namespace = mocker.patch.object(
inventory, "get_ssh_services_for_namespace", return_value=[]
)
add_host = mocker.patch.object(
inventory, "add_host", side_effect=add_host_side_effects
)
set_vars_from_vm = mocker.patch.object(inventory, "set_vars_from_vm")
set_vars_from_vmi = mocker.patch.object(inventory, "set_vars_from_vmi")
set_composable_vars = mocker.patch.object(inventory, "set_composable_vars")
inventory.populate_inventory_from_namespace(None, "test", DEFAULT_NAMESPACE, opts)
# These should always get called once
get_vms_for_namespace.assert_called_once_with(None, DEFAULT_NAMESPACE, opts)
get_vmis_for_namespace.assert_called_once_with(None, DEFAULT_NAMESPACE, opts)
# Assert it tries to add the expected vars for all provided VMs/VMIs
set_vars_from_vm.assert_has_calls(set_vars_from_vm_calls)
set_vars_from_vmi.assert_has_calls(set_vars_from_vmi_calls)
set_composable_vars.assert_has_calls(set_composable_vars_calls)
# If no VMs or VMIs were provided the function should not add any groups
if vms or vmis:
get_ssh_services_for_namespace.assert_called_once_with(None, DEFAULT_NAMESPACE)
assert list(groups.keys()) == ["test", f"namespace_{DEFAULT_NAMESPACE}"]
else:
get_ssh_services_for_namespace.assert_not_called()
assert not list(groups.keys())
# Assert the expected amount of hosts was added
add_host.assert_has_calls(add_host_calls)
assert len(add_host_calls) == expected

View File

@@ -0,0 +1,286 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from addict import Dict
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
@pytest.mark.parametrize(
"opts",
[
InventoryOptions(),
InventoryOptions(kube_secondary_dns=True), # needs network_name
InventoryOptions(use_service=True), # needs service
],
)
def test_use_ip_address_by_default(mocker, inventory, opts):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
ip_address = "1.1.1.1"
inventory.set_ansible_host_and_port(Dict(), hostname, ip_address, None, opts)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", ip_address),
mocker.call(hostname, "ansible_port", None),
]
)
@pytest.mark.parametrize(
"base_domain",
[
True,
False,
],
)
def test_kube_secondary_dns(mocker, inventory, base_domain):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
vmi = Dict(
{
"metadata": {"name": "testvm", "namespace": "default"},
"status": {"interfaces": [{"name": "awesome"}]},
}
)
inventory.set_ansible_host_and_port(
vmi,
hostname,
"1.1.1.1",
None,
InventoryOptions(
kube_secondary_dns=True,
network_name="awesome",
base_domain="example.com" if base_domain else None,
),
)
ansible_host = "awesome.testvm.default.vm"
if base_domain:
ansible_host += ".example.com"
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", ansible_host),
mocker.call(hostname, "ansible_port", None),
]
)
def test_kube_secondary_dns_precedence_over_service(mocker, inventory):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
vmi = Dict(
{
"metadata": {"name": "testvm", "namespace": "default"},
"status": {"interfaces": [{"name": "awesome"}]},
}
)
inventory.set_ansible_host_and_port(
vmi,
hostname,
"1.1.1.1",
{"metadata": {"name": "testsvc"}},
InventoryOptions(
kube_secondary_dns=True, network_name="awesome", use_service=True
),
)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", "awesome.testvm.default.vm"),
mocker.call(hostname, "ansible_port", None),
]
)
@pytest.mark.parametrize(
"service,expected_host,expected_port",
[
(
{
"spec": {
"type": "LoadBalancer",
"ports": [{"port": 22}],
},
"status": {
"loadBalancer": {"ingress": [{"hostname": "testhost.example.com"}]}
},
},
"testhost.example.com",
22,
),
(
{
"spec": {
"type": "LoadBalancer",
"ports": [{"port": 23}],
},
"status": {
"loadBalancer": {
"ingress": [
{"hostname": "testhost.example.com", "ip": "2.2.2.2"}
]
}
},
},
"testhost.example.com",
23,
),
(
{
"spec": {
"type": "LoadBalancer",
"ports": [{"port": 24}],
},
"status": {"loadBalancer": {"ingress": [{"ip": "2.2.2.2"}]}},
},
"2.2.2.2",
24,
),
(
{
"spec": {
"type": "NodePort",
"ports": [{"nodePort": 25}],
},
},
"testnode.example.com",
25,
),
],
)
def test_service(mocker, inventory, service, expected_host, expected_port):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
vmi = Dict(
{
"status": {
"nodeName": "testnode.example.com",
},
}
)
inventory.set_ansible_host_and_port(
vmi,
hostname,
"1.1.1.1",
service,
InventoryOptions(use_service=True),
)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", expected_host),
mocker.call(hostname, "ansible_port", expected_port),
]
)
def test_service_append_base_domain(mocker, inventory):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
vmi = Dict(
{
"status": {
"nodeName": "testnode",
},
}
)
service = {
"spec": {
"type": "NodePort",
"ports": [{"nodePort": 25}],
},
}
inventory.set_ansible_host_and_port(
vmi,
hostname,
"1.1.1.1",
service,
InventoryOptions(
use_service=True, append_base_domain=True, base_domain="awesome.com"
),
)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", "testnode.awesome.com"),
mocker.call(hostname, "ansible_port", 25),
]
)
@pytest.mark.parametrize(
"host,port",
[
("testhost.com", None),
(None, 22),
(None, None),
],
)
def test_service_fallback(mocker, inventory, host, port):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
mocker.patch.object(inventory, "get_host_from_service", return_value=host)
mocker.patch.object(inventory, "get_port_from_service", return_value=port)
hostname = "default-testvm"
vmi = Dict(
{
"status": {
"nodeName": "testnode",
},
}
)
inventory.set_ansible_host_and_port(
vmi,
hostname,
"1.1.1.1",
{"something": "something"},
InventoryOptions(use_service=True),
)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", "1.1.1.1"),
mocker.call(hostname, "ansible_port", None),
]
)
def test_no_service_if_network_name(mocker, inventory):
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
inventory.set_ansible_host_and_port(
Dict(),
hostname,
"1.2.3.4",
{"something": "something"},
InventoryOptions(use_service=True, network_name="awesome"),
)
set_variable.assert_has_calls(
[
mocker.call(hostname, "ansible_host", "1.2.3.4"),
mocker.call(hostname, "ansible_port", None),
]
)

View File

@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from random import choice
from string import ascii_lowercase
import pytest
from addict import Dict
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
)
@pytest.mark.parametrize(
"obj,expected",
[
(
{
"metadata": {
"something": "idontcare",
},
},
{},
),
(
{
"metadata": {
"annotations": {"testanno": "testval"},
},
},
{"annotations": {"testanno": "testval"}},
),
(
{
"metadata": {
"labels": {"testlabel": "testval"},
},
},
{"labels": {"testlabel": "testval"}},
),
(
{
"metadata": {
"resourceVersion": "123",
},
},
{"resource_version": "123"},
),
(
{
"metadata": {
"uid": "48e6ed2c-d8a2-4172-844d-0fe7056aa180",
},
},
{"uid": "48e6ed2c-d8a2-4172-844d-0fe7056aa180"},
),
(
{
"status": {
"interfaces": [{"ipAddress": "10.10.10.10"}],
},
},
{"interfaces": [{"ipAddress": "10.10.10.10"}]},
),
],
)
def test_set_common_vars(inventory, hosts, obj, expected):
hostname = "default-testvm"
prefix = "".join(choice(ascii_lowercase) for i in range(5))
inventory.inventory.add_host(hostname)
inventory.set_common_vars(hostname, prefix, Dict(obj), InventoryOptions())
for key, value in expected.items():
prefixed_key = f"{prefix}_{key}"
assert prefixed_key in hosts[hostname]
assert hosts[hostname][prefixed_key] == value
@pytest.mark.parametrize(
"create_groups",
[
True,
False,
],
)
def test_set_common_vars_create_groups(mocker, inventory, create_groups):
mocker.patch.object(inventory.inventory, "set_variable")
set_groups_from_labels = mocker.patch.object(inventory, "set_groups_from_labels")
hostname = "default-testvm"
labels = {"testkey": "testval"}
opts = InventoryOptions(create_groups=create_groups)
inventory.set_common_vars(
hostname, "prefix", Dict({"metadata": {"labels": labels}}), opts
)
if create_groups:
set_groups_from_labels.assert_called_once_with(hostname, labels)
else:
set_groups_from_labels.assert_not_called()
def test_called_by_set_vars_from(mocker, inventory):
hostname = "default-testvm"
opts = InventoryOptions()
set_common_vars = mocker.patch.object(inventory, "set_common_vars")
inventory.set_vars_from_vm(hostname, Dict(), opts)
inventory.set_vars_from_vmi(hostname, Dict(), {}, opts)
set_common_vars.assert_has_calls(
[mocker.call(hostname, "vm", {}, opts), mocker.call(hostname, "vmi", {}, opts)]
)

View File

@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from addict import Dict
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
InventoryOptions,
LABEL_KUBEVIRT_IO_DOMAIN,
)
def test_ignore_vmi_without_interface(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
set_ansible_host_and_port = mocker.patch.object(
inventory, "set_ansible_host_and_port"
)
vmi = Dict({"status": {}})
inventory.set_vars_from_vmi("default-testvm", vmi, {}, InventoryOptions())
set_ansible_host_and_port.assert_not_called()
def test_use_first_interface_by_default(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
set_ansible_host_and_port = mocker.patch.object(
inventory, "set_ansible_host_and_port"
)
hostname = "default-testvm"
vmi = Dict(
{"status": {"interfaces": [{"ipAddress": "1.1.1.1"}, {"ipAddress": "2.2.2.2"}]}}
)
opts = InventoryOptions()
inventory.set_vars_from_vmi(hostname, vmi, {}, opts)
set_ansible_host_and_port.assert_called_once_with(
vmi, hostname, "1.1.1.1", None, opts
)
def test_use_named_interface(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
set_ansible_host_and_port = mocker.patch.object(
inventory, "set_ansible_host_and_port"
)
hostname = "default-testvm"
vmi = Dict(
{
"status": {
"interfaces": [
{"name": "first", "ipAddress": "1.1.1.1"},
{"name": "second", "ipAddress": "2.2.2.2"},
]
}
}
)
opts = InventoryOptions(network_name="second")
inventory.set_vars_from_vmi(hostname, vmi, {}, opts)
set_ansible_host_and_port.assert_called_once_with(
vmi, hostname, "2.2.2.2", None, opts
)
def test_ignore_vmi_without_named_interface(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
set_ansible_host_and_port = mocker.patch.object(
inventory, "set_ansible_host_and_port"
)
vmi = Dict(
{"status": {"interfaces": [{"name": "somename", "ipAddress": "1.1.1.1"}]}}
)
inventory.set_vars_from_vmi(
"default-testvm", vmi, {}, InventoryOptions(network_name="awesome")
)
set_ansible_host_and_port.assert_not_called()
def test_set_winrm_if_windows(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
mocker.patch.object(inventory, "is_windows", return_value=True)
mocker.patch.object(inventory, "set_ansible_host_and_port")
set_variable = mocker.patch.object(inventory.inventory, "set_variable")
hostname = "default-testvm"
vmi = Dict({"status": {"interfaces": [{"ipAddress": "1.1.1.1"}]}})
inventory.set_vars_from_vmi(hostname, vmi, {}, InventoryOptions())
set_variable.assert_called_once_with(hostname, "ansible_connection", "winrm")
def test_service_lookup(mocker, inventory):
mocker.patch.object(inventory, "set_common_vars")
set_ansible_host_and_port = mocker.patch.object(
inventory, "set_ansible_host_and_port"
)
hostname = "default-testvm"
vmi = Dict(
{
"metadata": {"labels": {LABEL_KUBEVIRT_IO_DOMAIN: "testdomain"}},
"status": {"interfaces": [{"name": "somename", "ipAddress": "1.1.1.1"}]},
}
)
opts = InventoryOptions()
service = {"metadata": {"name": "testsvc"}}
inventory.set_vars_from_vmi(hostname, vmi, {"testdomain": service}, opts)
set_ansible_host_and_port.assert_called_once_with(
vmi, hostname, "1.1.1.1", service, opts
)

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from ansible_collections.kubevirt.core.plugins.inventory import (
kubevirt,
)
from ansible_collections.kubevirt.core.plugins.inventory.kubevirt import (
KubeVirtInventoryException,
)
@pytest.mark.parametrize(
"cache",
[
True,
False,
],
)
def test_cache_is_used(mocker, inventory, cache):
connections = [{"test-conn": {}}]
config_data = {"connections": connections}
cache_key = "test-prefix"
mocker.patch.dict(inventory._cache, {cache_key: {"test-key": "test-value"}})
fetch_objects = mocker.patch.object(inventory, "fetch_objects")
inventory.setup(config_data, cache, cache_key)
if cache:
fetch_objects.assert_not_called()
else:
fetch_objects.assert_called_once_with(connections)
@pytest.mark.parametrize(
"present",
[
True,
False,
],
)
def test_k8s_client_missing(mocker, inventory, present):
mocker.patch.object(kubevirt, "HAS_K8S_MODULE_HELPER", present)
fetch_objects = mocker.patch.object(inventory, "fetch_objects")
if present:
inventory.setup({}, False, "test")
fetch_objects.assert_called_once()
else:
with pytest.raises(
KubeVirtInventoryException,
match="This module requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: None",
):
inventory.setup({}, False, "test")
fetch_objects.assert_not_called()

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Red Hat, Inc.
# Apache License 2.0 (see LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@pytest.mark.parametrize(
"file_name,expected",
[
("inventory.kubevirt.yml", True),
("inventory.kubevirt.yaml", True),
("something.kubevirt.yml", True),
("something.kubevirt.yaml", True),
("inventory.somethingelse.yml", False),
("inventory.somethingelse.yaml", False),
("something.somethingelse.yml", False),
("something.somethingelse.yaml", False),
],
)
def test_verify_file(tmp_path, inventory, file_name, expected):
file = tmp_path / file_name
file.touch()
assert inventory.verify_file(str(file)) is expected
@pytest.mark.parametrize(
"file_name",
[
"inventory.kubevirt.yml",
"inventory.kubevirt.yaml",
"something.kubevirt.yml",
"something.kubevirt.yaml",
"inventory.somethingelse.yml",
"inventory.somethingelse.yaml",
"something.somethingelse.yml",
"something.somethingelse.yaml",
],
)
def test_verify_file_bad_config(inventory, file_name):
assert inventory.verify_file(file_name) is False