You've already forked ansible-netbox-inventory
seed.py populates the stack through the API: a read-only user with a self-provisioned token, tenants, sites, clusters, a VRF, virtual machines (one with a primary IP) and standalone addresses; the tests run the real inventory script against every source/filter combination, every error path and the ansible --list/--host protocol.
166 lines
6.9 KiB
Python
166 lines
6.9 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
"""
|
|
End-to-end tests: every source/filter scenario against a live NetBox.
|
|
|
|
The dataset these expectations rest on is created by seed.py:
|
|
tenants customer1/customer2, sites milan/turin, clusters cluster1 (milan) and
|
|
cluster2 (turin), VRF internal, VMs vm01 (cluster1, customer1, primary IP
|
|
192.0.2.20 named vm01.example.com), vm02 (cluster1, customer2, no primary IP)
|
|
and vm03.example.com (cluster2), plus standalone addresses 192.0.2.10
|
|
(web.example.com, customer1), 192.0.2.11 (unnamed, internal), 192.0.2.12
|
|
(web.example.com duplicate) and 192.0.2.13 (db.other.org, customer2, internal).
|
|
"""
|
|
|
|
|
|
def hosts(result) -> set[str]:
|
|
return set(result.inventory["netbox"]["hosts"])
|
|
|
|
|
|
def hostvars(result) -> dict:
|
|
return result.inventory["_meta"]["hostvars"]
|
|
|
|
|
|
class TestIpAddressSource:
|
|
def test_all_addresses(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses")
|
|
assert result.returncode == 0, result.stderr
|
|
# the duplicate DNS name 192.0.2.12 falls back to its bare address
|
|
assert hosts(result) == {
|
|
"web.example.com",
|
|
"192.0.2.11",
|
|
"192.0.2.12",
|
|
"db.other.org",
|
|
"vm01.example.com",
|
|
}
|
|
web = hostvars(result)["web.example.com"]
|
|
assert web["ansible_host"] == "192.0.2.10"
|
|
assert web["netbox_tenant"] == "customer1"
|
|
assert hostvars(result)["192.0.2.11"]["netbox_vrf"] == "internal"
|
|
|
|
def test_tenant_filter(self, run_inventory):
|
|
result = run_inventory(
|
|
source="ip-addresses", filter_name="tenant", filter_value="customer1"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"web.example.com"}
|
|
|
|
def test_named_filter_deduplicates(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", filter_name="named")
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"web.example.com", "db.other.org", "vm01.example.com"}
|
|
|
|
def test_named_false_keeps_unnamed(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", filter_name="named", filter_value="false")
|
|
assert result.returncode == 0, result.stderr
|
|
assert "192.0.2.11" in hosts(result)
|
|
|
|
def test_vrf_filter(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", filter_name="vrf", filter_value="internal")
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"192.0.2.11", "db.other.org"}
|
|
|
|
def test_domain_filter(self, run_inventory):
|
|
result = run_inventory(
|
|
source="ip-addresses", filter_name="domain", filter_value="example.com"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"web.example.com", "192.0.2.12", "vm01.example.com"}
|
|
|
|
def test_domain_filter_other_domain(self, run_inventory):
|
|
result = run_inventory(
|
|
source="ip-addresses", filter_name="domain", filter_value="other.org"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"db.other.org"}
|
|
|
|
|
|
class TestVirtualMachineSource:
|
|
def test_all_virtual_machines(self, run_inventory):
|
|
result = run_inventory(source="virtual-machines")
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"vm01", "vm02", "vm03.example.com"}
|
|
vm01 = hostvars(result)["vm01"]
|
|
assert vm01["ansible_host"] == "192.0.2.20"
|
|
assert vm01["netbox_cluster"] == "cluster1"
|
|
assert vm01["netbox_site"] == "milan"
|
|
assert vm01["netbox_tenant"] == "customer1"
|
|
assert vm01["netbox_status"] == "active"
|
|
# no primary IP -> no ansible_host, Ansible resolves the name
|
|
assert "ansible_host" not in hostvars(result)["vm02"]
|
|
|
|
def test_tenant_filter(self, run_inventory):
|
|
result = run_inventory(
|
|
source="virtual-machines", filter_name="tenant", filter_value="customer2"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"vm02"}
|
|
|
|
def test_cluster_filter(self, run_inventory):
|
|
result = run_inventory(
|
|
source="virtual-machines", filter_name="cluster", filter_value="cluster1"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"vm01", "vm02"}
|
|
|
|
def test_site_filter(self, run_inventory):
|
|
result = run_inventory(source="virtual-machines", filter_name="site", filter_value="turin")
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"vm03.example.com"}
|
|
|
|
def test_domain_filter(self, run_inventory):
|
|
result = run_inventory(
|
|
source="virtual-machines", filter_name="domain", filter_value="example.com"
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
assert hosts(result) == {"vm03.example.com"}
|
|
|
|
|
|
class TestErrorScenarios:
|
|
def test_unknown_tenant_name(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", filter_name="tenant", filter_value="ghost")
|
|
assert result.returncode == 1
|
|
assert 'No tenant named "ghost"' in result.stderr
|
|
|
|
def test_filter_source_mismatch(self, run_inventory):
|
|
result = run_inventory(
|
|
source="virtual-machines", filter_name="vrf", filter_value="internal"
|
|
)
|
|
assert result.returncode == 1
|
|
assert "does not apply" in result.stderr
|
|
|
|
def test_unknown_filter(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", filter_name="rack", filter_value="r1")
|
|
assert result.returncode == 1
|
|
assert "Unknown filter" in result.stderr
|
|
|
|
def test_unknown_source(self, run_inventory):
|
|
result = run_inventory(source="devices")
|
|
assert result.returncode == 1
|
|
assert "Unknown source" in result.stderr
|
|
|
|
def test_missing_filter_value(self, run_inventory):
|
|
result = run_inventory(source="virtual-machines", filter_name="cluster")
|
|
assert result.returncode == 1
|
|
assert "requires a value" in result.stderr
|
|
|
|
def test_invalid_token(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses", token="wrong-token")
|
|
assert result.returncode == 1
|
|
assert "NetBox API error" in result.stderr
|
|
|
|
|
|
class TestInventoryProtocol:
|
|
def test_host_returns_empty_vars(self, run_inventory):
|
|
result = run_inventory(args=("--host", "web.example.com"))
|
|
assert result.returncode == 0
|
|
assert result.inventory == {}
|
|
|
|
def test_list_structure(self, run_inventory):
|
|
result = run_inventory(source="ip-addresses")
|
|
assert result.returncode == 0, result.stderr
|
|
inventory = result.inventory
|
|
assert set(inventory) == {"netbox", "_meta"}
|
|
assert inventory["netbox"]["hosts"] == sorted(inventory["netbox"]["hosts"])
|
|
assert set(inventory["netbox"]["hosts"]) == set(inventory["_meta"]["hostvars"])
|