Skip to content

Commit

Permalink
Add toggle for pynautobot dict object and add test coverage nautobot#4
Browse files Browse the repository at this point in the history
  • Loading branch information
pke11y committed Jun 8, 2021
1 parent 27e1f4d commit d45c7d1
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 82 deletions.
5 changes: 4 additions & 1 deletion nornir_nautobot/plugins/inventory/nautobot.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ def __init__(
nautobot_token: Union[str, None],
ssl_verify: Union[bool, None] = True,
filter_parameters: Union[Dict[str, Any], None] = None,
pynautobot_dict: Union[bool, None] = True,
) -> None:
"""Nautobot nornir class initialization."""
self.nautobot_url = nautobot_url or os.getenv("NAUTOBOT_URL")
self.nautobot_token = nautobot_token or os.getenv("NAUTOBOT_TOKEN")
self.filter_parameters = filter_parameters
self.ssl_verify = ssl_verify
self.pynautobot_dict = pynautobot_dict
self._verify_required()
self._api_session = None
self._devices = None
Expand Down Expand Up @@ -140,7 +142,8 @@ def load(self) -> Inventory:
host["data"]["pynautobot_object"] = device

# Create dictionary object available for filtering
host["data"]["pynautobot_dictionary"] = dict(device)
if self.pynautobot_dict:
host["data"]["pynautobot_dictionary"] = dict(device)
# TODO: #3 Investigate Nornir compatability with dictionary like object

# Add Primary IP address, if found. Otherwise add hostname as the device name
Expand Down
96 changes: 96 additions & 0 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
"""Used to setup fixtures to be used through tests."""
import pytest
from nornir_nautobot.plugins.inventory.nautobot import NautobotInventory
from nornir import InitNornir
from os import path

# GLOBALS
HERE = path.abspath(path.dirname(__file__))
MOCK_API_CALLS = [
{
"fixture_path": f"{HERE}/mocks/01_get_devices.json",
"url": "http://mock.example.com/api/dcim/devices/",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/02_get_device1.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-dist01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/03_get_device2.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-dist02",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/04_get_device3.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-wan01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/05_get_sites_filtered.json",
"url": "http://mock.example.com/api/dcim/devices/?site=msp",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/06_get_device_msp-rtr01.json",
"url": "http://mock.example.com/api/dcim/devices/?name=msp-rtr01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/07_get_device_msp-rtr02.json",
"url": "http://mock.example.com/api/dcim/devices/?name=msp-rtr02",
"method": "get",
},
]


@pytest.fixture()
def mock_api_calls(requests_mock):
"""Loads API calls for mocker
Args:
mock (Request Mock): Requests Mock instance
"""
for api_call in MOCK_API_CALLS:
with open(api_call["fixture_path"], "r") as _file:
api_call["text"] = _file.read()
requests_mock.request(method=api_call["method"], url=api_call["url"], text=api_call["text"], complete_qs=True)


@pytest.fixture()
Expand All @@ -11,3 +66,44 @@ def nornir_nautobot_class():
(bool): Returns True
"""
return NautobotInventory(nautobot_url="http://mock.example.com", nautobot_token="0123456789abcdef01234567890")


@pytest.fixture()
def nornir_no_pynb_dict(mock_api_calls):
"""
Nautobot Inventory without pynautobot dict set
Returns:
(NautobotInventory): inventory
"""
return InitNornir(
inventory={
"plugin": "NautobotInventory",
"options": {
"nautobot_url": "http://mock.example.com",
"nautobot_token": "0123456789abcdef01234567890",
"pynautobot_dict": False,
},
},
logging={"enabled": False},
)


@pytest.fixture()
def nornir_with_pynb_dict(mock_api_calls):
"""
Nautobot Inventory with pynautobot dict toggle to True
Returns:
(NautobotInventory): inventory
"""
return InitNornir(
inventory={
"plugin": "NautobotInventory",
"options": {
"nautobot_url": "http://mock.example.com",
"nautobot_token": "0123456789abcdef01234567890",
},
},
logging={"enabled": False},
)
119 changes: 38 additions & 81 deletions tests/unit/test_nautobot_inventory.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,16 @@
"""Pytest of Nautobot Inventory."""
# Standard Library Imports
from os import path
from itertools import chain

# Third Party Imports
import pytest
from requests.sessions import Session
import pynautobot
from requests_mock import Mocker

# Application Imports
from nornir_nautobot.plugins.inventory.nautobot import NautobotInventory

# GLOBALS
HERE = path.abspath(path.dirname(__file__))
API_CALLS = [
{
"fixture_path": f"{HERE}/mocks/01_get_devices.json",
"url": "http://mock.example.com/api/dcim/devices/",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/02_get_device1.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-dist01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/03_get_device2.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-dist02",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/04_get_device3.json",
"url": "http://mock.example.com/api/dcim/devices/?name=den-wan01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/05_get_sites_filtered.json",
"url": "http://mock.example.com/api/dcim/devices/?site=msp",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/06_get_device_msp-rtr01.json",
"url": "http://mock.example.com/api/dcim/devices/?name=msp-rtr01",
"method": "get",
},
{
"fixture_path": f"{HERE}/mocks/07_get_device_msp-rtr02.json",
"url": "http://mock.example.com/api/dcim/devices/?name=msp-rtr02",
"method": "get",
},
]

# Functions for helping tests
def load_api_calls(mock):
"""Loads API calls for mocker
Args:
mock (Request Mock): Requests Mock instance
"""
for api_call in API_CALLS:
with open(api_call["fixture_path"], "r") as _file:
api_call["text"] = _file.read()

mock.request(method=api_call["method"], url=api_call["url"], text=api_call["text"], complete_qs=True)


#
# Tests
#
Expand Down Expand Up @@ -108,29 +54,40 @@ def test_pynautobot_obj(nornir_nautobot_class):
assert isinstance(nornir_nautobot_class.pynautobot_obj, pynautobot.api)


def test_devices(nornir_nautobot_class):
# Import mock requests
with Mocker() as mock:
load_api_calls(mock)
pynautobot_obj = pynautobot.api(url="http://mock.example.com", token="0123456789abcdef01234567890")
expected_devices = []
for device in ["den-dist01", "den-dist02", "den-wan01"]:
expected_devices.append(pynautobot_obj.dcim.devices.get(name=device))

assert nornir_nautobot_class.devices == expected_devices


def test_filter_devices():
with Mocker() as mock:
load_api_calls(mock)
test_class = NautobotInventory(
nautobot_url="http://mock.example.com",
nautobot_token="0123456789abcdef01234567890",
filter_parameters={"site": "msp"},
)
pynautobot_obj = pynautobot.api(url="http://mock.example.com", token="0123456789abcdef01234567890")
expected_devices = []
for device in ["msp-rtr01", "msp-rtr02"]:
expected_devices.append(pynautobot_obj.dcim.devices.get(name=device))

assert test_class.devices == expected_devices
def test_devices(mock_api_calls, nornir_nautobot_class):
pynautobot_obj = pynautobot.api(url="http://mock.example.com", token="0123456789abcdef01234567890")
expected_devices = []
for device in ["den-dist01", "den-dist02", "den-wan01"]:
expected_devices.append(pynautobot_obj.dcim.devices.get(name=device))

assert nornir_nautobot_class.devices == expected_devices


def test_filter_devices(mock_api_calls):
test_class = NautobotInventory(
nautobot_url="http://mock.example.com",
nautobot_token="0123456789abcdef01234567890",
filter_parameters={"site": "msp"},
)
pynautobot_obj = pynautobot.api(url="http://mock.example.com", token="0123456789abcdef01234567890")
expected_devices = []
for device in ["msp-rtr01", "msp-rtr02"]:
expected_devices.append(pynautobot_obj.dcim.devices.get(name=device))

assert test_class.devices == expected_devices


def test_pynautobot_as_dict(nornir_no_pynb_dict, nornir_with_pynb_dict):
"""
Test the pynautobot flag sets the presence of a 'pynautobot_dictionary' data attribute
"""
keys_with_dict = [
nornir_with_pynb_dict.inventory.hosts[device].keys() for device in ["den-dist01", "den-dist02", "den-wan01"]
]
keys_no_dict = [
nornir_no_pynb_dict.inventory.hosts[device].keys() for device in ["den-dist01", "den-dist02", "den-wan01"]
]
attrs_with_dict = set(chain(*keys_with_dict))
attrs_no_dict = set(chain(*keys_no_dict))
attrs_diff = attrs_with_dict - attrs_no_dict
assert attrs_diff == set(["pynautobot_dictionary"])

0 comments on commit d45c7d1

Please sign in to comment.