Demo For Common Ansible Action-Plugin Based Testing Strategy for ND 4… - #337
Demo For Common Ansible Action-Plugin Based Testing Strategy for ND 4…#337astawast-cisco wants to merge 25 commits into
Conversation
apply_changed maps to the first real module run, and idempotency: true validates that the second run reports changed=false
…D querying and validation mechanism
…odule_utils/ndi.py
…ccess, to align with the proposal approach
|
Can we add unit tests for the action plugin? |
…cific IP address with the reserved documentation placeholder 192.0.2.1
|
Medium: predictive check mode does not verify that controller state stayed unchanged The harness currently trusts the target module’s check-mode implementation. During predictive check mode, it:
It does not:
The target module normally performs GET requests to calculate its predicted changes, but that does not prove it avoided a write. Also, the configured To verify check-mode safety, the sequence should be: For an interface test, the snapshot should cover all relevant managed interfaces on the test switch—not just the requested interface—so an unintended mutation to another interface is also detected. The cleanest enhancement would be for the harness to support something like: check_mode_queries:
- name: Snapshot managed interfaces
path: >-
/api/v1/manage/fabrics/{{ fabric_name
}}/switches/{{ switch_id }}/interfacesThe harness would run that query before and after predictive check mode and require equivalent normalized controller state before proceeding. The current phase verifies the module’s reported prediction; it does not verify that predictive execution was mutation-free. |
|
Medium: add a contributor guide for writing integration tests with this framework The PR explains the framework’s purpose and demonstrates it with loopback and Ethernet-access playbooks, but it does not provide a clear authoring guide for a contributor migrating another module. The Could we add an authoritative guide such as: At minimum, it should document:
Without this guide, the PR demonstrates the framework but does not yet make it straightforward for another contributor to use it consistently or confirm that a module’s original integration coverage has been preserved and it will help our team review it's capabilities. |
|
Medium: demonstrate full test parity for all four migrated modules Before treating this framework as complete, could we migrate every existing integration-test scenario for:
The current demos prove that the framework supports selected workflows, but they do not yet demonstrate that it can preserve the modules’ complete existing test coverage. Exercising all four full suites would also expose framework gaps that simplified examples may not reveal. For each module, please:
The migrated coverage should include, where applicable:
Setup, feature-specific assertions, and cleanup can remain in the module-specific playbooks where appropriate; the framework does not need to internalize every responsibility. However, every original behavior should have an identifiable replacement. If an existing scenario cannot be represented cleanly, that should be treated as a framework gap to address rather than dropping or weakening the test. The original suites should only be retired after the parity mapping and replacement runs are complete. |
|
I was trying to use this framework for the Interface Groups integration tests and noticed one possible improvement around idempotency. The second execution currently verifies Could you please evaluate supporting an optional expectation such as: expected:
idempotency:
changed: false
failed: false
non_get_call_count: 0The harness can calculate this from the idempotency result fields This would detect redundant |
|
I was trying to use this framework for the Interface Groups integration tests and noticed another area that could improve negative-test validation. Currently, phase expectations validate only Could you please evaluate supporting a per-phase message assertion, for example: expected:
apply:
changed: false
failed: true
msg_contains: "does not exist"This could validate the |
Current Progress
This repository contains a proof of concept (POC) for the proposed common Ansible action-plugin based testing strategy for ND 4.x integration tests. The goal is to demonstrate how common integration test logic can be centralized while allowing module-specific validations to remain within individual test playbooks.
Objectives Achieved
Implemented a reusable action plugin: " plugins/action/nd4x_module_test.py "
The plugin standardizes the common integration test workflow by executing:
This removes the need for every module test to duplicate the same execution logic.
The shared action plugin has been demonstrated using the nd_interface_loopback module.
Demo state playbooks have been created for:
This validates that the same execution framework can support multiple module states without changing the core testing logic.
A lightweight sanity workflow has been introduced for faster validation during pull requests.
The demo flow consists of:
This provides a faster alternative to executing the complete integration test suite while preserving confidence in basic functionality.
The plugin now supports a simplified expected-result schema:
expected:
check_mode_changed: true
apply_changed: true
idempotency: true
failed: false
This improves readability compared to previous run-specific expectations and provides a consistent contract across modules.
ND API validation has been added to the action plugin as an optional validation step after module execution.
The plugin supports:
Executing ND REST API queries through cisco.nd.nd_rest
Validating API responses using JSONPath expressions
Comparing actual API response values with expected values
Supporting expected HTTP status codes, including 404 for deleted resources
Reporting ND API validation failures as part of the same test execution flow
This allows a test to verify not only the module return result, but also the actual state present in the ND controller.
Example use cases include:
Validating that an interface was created successfully
Validating that interface attributes were updated correctly
Validating that a deleted resource is absent by expecting an HTTP 404 response
Current implementation supports both positive ND API validation and deleted-resource validation.
The testing framework intentionally separates responsibilities.
The shared action plugin handles generic testing behavior such as:
Individual module playbooks continue to contain feature-specific validations, such as verifying interface configuration, descriptions, IP addresses, or resource absence.
This keeps the framework reusable across different ND modules.
Cleanup is performed through Ansible always blocks to ensure test resources are removed regardless of test success or failure, preventing leftover configuration from affecting subsequent test runs.
During development, several integration issues were resolved, including:
Current Status
The proof of concept demonstrates that a shared action-plugin based framework can successfully centralize common ND 4.x integration test behavior while keeping module-specific assertions independent.
Steps to run the ND4.x demo playbook
Go to the collection root:
cd /Users//ansible_collections/cisco/nd
Install/check required collections:
ansible-galaxy collection install ansible.netcommon ansible.utils
Create local inventory :
cp tests/integration/inventory.networking tests/integration/inventory.LOCAL.networking
Update local inventory values:
ansible_host=
ansible_user=
ansible_password=
nd_test_fabric_name=
nd_test_switch_ip=
nd_test_switch_id=<switch id/serial>
Run the demo sanity flow:
ANSIBLE_CONFIG=ansible.cfg
ANSIBLE_COLLECTIONS_PATH=/Users/:/Users//.ansible/collections:/usr/share/ansible/collections
python -m ansible_test._util.target.cli.ansible_test_cli_stub
network-integration nd_interface_loopback
--inventory tests/integration/inventory.LOCAL.networking
--tags nd4x_demo
-vvv
To run one state only, replace the tag:
--tags nd4x_demo_merged
--tags nd4x_demo_replaced
--tags nd4x_demo_overridden
--tags nd4x_demo_deleted
Expected result:
PLAY RECAP should show failed=0