Skip to content
58 changes: 53 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
- name: Check out code
uses: actions/checkout@v4

- name: Set up Python 3.10.14
- name: Set up Python 3.11.9
uses: actions/setup-python@v5
with:
python-version: 3.10.14
python-version: 3.11.9

- name: Install ansible-base (v${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/v${{ matrix.ansible }}.tar.gz --disable-pip-version-check
Expand All @@ -51,12 +51,12 @@ jobs:
strategy:
matrix:
ansible: [2.14.15, 2.15.10, 2.16.5, 2.17.8]
python: ['3.10']
python: ['3.11']
steps:
- name: Set up Python 3.10.14
- name: Set up Python 3.11.9
uses: actions/setup-python@v5
with:
python-version: 3.10.14
python-version: 3.11.9

- name: Upgrade pip
run: |
Expand All @@ -77,3 +77,51 @@ jobs:
- name: Run sanity tests
run: ansible-test sanity --docker --python ${{matrix.python}} -v --color --truncate 0
working-directory: /home/runner/.ansible/collections/ansible_collections/cisco/nac_dc_vxlan

unit:
name: Unit (Ⓐ${{ matrix.ansible }})
needs:
- build
runs-on: ubuntu-latest
strategy:
matrix:
ansible: [2.14.15, 2.15.10, 2.16.5, 2.17.8]
python: ['3.11']
steps:
- name: Set up Python 3.11.9
uses: actions/setup-python@v5
with:
python-version: 3.11.9

- name: Upgrade pip
run: |
pip install --upgrade pip

- name: Install ansible-base (v${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/v${{ matrix.ansible }}.tar.gz --disable-pip-version-check

- name: Download migrated collection artifacts
uses: actions/download-artifact@v4
with:
name: collection-${{ matrix.ansible }}
path: .cache/collection-tarballs

- name: Install iac-validate (v0.2.7)
run: pip install iac-validate==0.2.7

- name: Install coverage (v7.9.2)
run: pip install coverage==7.9.2

- name: Install pytest (v8.4.1)
run: pip install pytest==8.4.1

- name: Install the collection tarball
run: ansible-galaxy collection install .cache/collection-tarballs/*.tar.gz

- name: Run unit tests
run: coverage run --source=. -m pytest tests/unit/. -vvvv
working-directory: /home/runner/.ansible/collections/ansible_collections/cisco/nac_dc_vxlan

- name: Generate coverage report
run: coverage report --include="plugins/*"
working-directory: /home/runner/.ansible/collections/ansible_collections/cisco/nac_dc_vxlan
4 changes: 2 additions & 2 deletions plugins/action/dtc/manage_child_fabric_networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from ansible.plugins.action import ActionBase
from ansible.template import Templar
from ansible.errors import AnsibleFileNotFound
from ansible_collections.cisco.nac_dc_vxlan.plugins.filter import version_compare
from ...filter.version_compare import version_compare


import re
Expand Down Expand Up @@ -202,7 +202,7 @@ def run(self, tmp=None, task_vars=None):
# Attempt to find and read the template file
role_path = task_vars.get('role_path')
version = '3.2'
if version_compare.version_compare(nd_major_minor_patch, '3.1.1', '<='):
if version_compare(nd_major_minor_patch, '3.1.1', '<='):
version = '3.1'
template_path = f"{role_path}{MSD_CHILD_FABRIC_NETWORK_TEMPLATE_PATH}{version}{MSD_CHILD_FABRIC_NETWORK_TEMPLATE}"

Expand Down
4 changes: 2 additions & 2 deletions plugins/action/dtc/manage_child_fabric_vrfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from ansible.plugins.action import ActionBase
from ansible.template import Templar
from ansible.errors import AnsibleFileNotFound
from ansible_collections.cisco.nac_dc_vxlan.plugins.filter import version_compare
from ...filter.version_compare import version_compare


import re
Expand Down Expand Up @@ -214,7 +214,7 @@ def run(self, tmp=None, task_vars=None):
# Attempt to find and read the template file
role_path = task_vars.get('role_path')
version = '3.2'
if version_compare.version_compare(nd_major_minor_patch, '3.1.1', '<='):
if version_compare(nd_major_minor_patch, '3.1.1', '<='):
version = '3.1'
template_path = f"{role_path}{MSD_CHILD_FABRIC_VRF_TEMPLATE_PATH}{version}{MSD_CHILD_FABRIC_VRF_TEMPLATE}"

Expand Down
2 changes: 2 additions & 0 deletions plugins/filter/version_compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@ def version_compare(version1, version2, op):
version1 (str): The first version string to compare.
version2 (str): The second version string to compare.
op (str): The comparison operator as a string. Supported: '==', '!=', '>', '>=', '<', '<='.

Returns:
bool: The result of the comparison.

Raises:
AnsibleError: If the 'packaging' library is not installed.
AnsibleFilterTypeError: If the version arguments are not strings.
Expand Down
Empty file.
100 changes: 100 additions & 0 deletions tests/unit/plugins/action/dtc/base_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Copyright (c) 2025 Cisco Systems, Inc. and its affiliates
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# SPDX-License-Identifier: MIT

"""
Base test class for DTC action plugins.
"""

import unittest
from unittest.mock import MagicMock
import os
import tempfile
import shutil

from ansible.playbook.task import Task
from ansible.template import Templar
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader


class ActionModuleTestCase(unittest.TestCase):
"""Base test case for action module tests."""

def setUp(self):
"""Set up test fixtures."""
self.loader = DataLoader()
self.inventory = InventoryManager(loader=self.loader, sources=[])
self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)

# Create mock task
self.task = Task()
self.task.args = {}
self.task.action = 'test_action'

# Create mock connection
self.connection = MagicMock()

# Create mock play context
self.play_context = MagicMock()

# Create mock loader
self.loader_mock = MagicMock()

# Create mock templar
self.templar = Templar(loader=self.loader, variables={})

# Create temporary directory for test files
self.temp_dir = tempfile.mkdtemp()

def tearDown(self):
"""Clean up test fixtures."""
# Clean up temporary directory
if os.path.exists(self.temp_dir):
shutil.rmtree(self.temp_dir)

def create_temp_file(self, content, filename=None):
"""Create a temporary file with given content."""
if filename is None:
fd, filepath = tempfile.mkstemp(dir=self.temp_dir, text=True)
with os.fdopen(fd, 'w') as f:
f.write(content)
else:
filepath = os.path.join(self.temp_dir, filename)
with open(filepath, 'w') as f:
f.write(content)
return filepath

def create_action_module(self, action_class, task_args=None):
"""Create an action module instance for testing."""
if task_args:
self.task.args = task_args

action_module = action_class(
task=self.task,
connection=self.connection,
play_context=self.play_context,
loader=self.loader_mock,
templar=self.templar,
shared_loader_obj=None
)

return action_module
Loading
Loading