diff options
Diffstat (limited to 'tests')
114 files changed, 2561 insertions, 11 deletions
diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..a16a5b0 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,121 @@ +# vyos.rest Test Framework + +Equivalent structure to `vyos.vyos` CLI collection tests, adapted for +the REST API connection model. + +## Structure + +``` +tests/ +├── unit/ +│ ├── modules/ +│ │ ├── base.py # VyOSModuleTestCase base class + load_fixture +│ │ ├── test_vyos_ntp_global.py +│ │ ├── test_vyos_logging_global.py +│ │ ├── test_vyos_prefix_lists.py +│ │ └── test_vyos_route_maps.py +│ └── fixtures/ +│ ├── ntp_global_running.json # Confirmed API responses from device +│ ├── logging_global_running.json +│ ├── prefix_lists_running.json +│ ├── route_maps_running.json +│ ├── snmp_server_running.json +│ └── lldp_global_running.json +└── integration/ + ├── network-integration.cfg + ├── inventory.network # Edit before running + └── targets/ + ├── vyos_ntp_global/tasks/main.yaml + ├── vyos_logging_global/tasks/main.yaml + ├── vyos_prefix_lists/tasks/main.yaml + ├── vyos_route_maps/tasks/main.yaml + ├── vyos_lldp_global/tasks/main.yaml + ├── vyos_snmp_server/tasks/main.yaml + ├── vyos_hostname/tasks/main.yaml + └── vyos_banner/tasks/main.yaml +``` + +## Unit Tests + +Unit tests cover: +- `normalize_config` / `normalize_running` — argspec and API parsing +- `build_commands` diff logic — all states (merged/replaced/overridden/deleted) +- Fixture-based parsing — confirmed API shapes from the actual device + +No device connection needed. Each test imports the module's functions +directly and calls them with mock data or fixture JSON. + +### Run all unit tests + +```bash +# From collection root +ansible-test units tests/unit/modules/ --python 3.12 + +# Or with pytest directly (no ansible-test required) +cd /path/to/ansible_collections/vyos/rest +python -m pytest tests/unit/modules/ -v +``` + +### Run a single module's tests + +```bash +ansible-test units tests/unit/modules/test_vyos_ntp_global.py --python 3.12 +python -m pytest tests/unit/modules/test_vyos_ntp_global.py -v +``` + +## Integration Tests + +Integration tests run against a live VyOS device. Each target: +1. Tears down any existing config for that resource +2. Tests merged (including idempotency) +3. Tests gathered +4. Tests replaced (including idempotency) +5. Tests deleted (including idempotency) +6. Tears down after + +### Prerequisites + +Edit `tests/integration/inventory.network` with your device details. + +### Run all integration tests + +```bash +ansible-test network-integration \ + --inventory tests/integration/inventory.network \ + vyos_* +``` + +### Run a single module's integration test + +```bash +ansible-test network-integration \ + --inventory tests/integration/inventory.network \ + vyos_ntp_global + +# Or with ansible-playbook directly +ansible-playbook \ + -i tests/integration/inventory.network \ + tests/integration/targets/vyos_ntp_global/tasks/main.yaml +``` + +## Adding Tests for a New Module + +1. Add a fixture: `tests/unit/fixtures/<module>_running.json` + - Copy the exact API response from a `curl showConfig` call + - This ensures tests reflect real device behaviour + +2. Add unit tests: `tests/unit/modules/test_<module>.py` + - Subclass `VyOSModuleTestCase` for fixture-based tests + - Test `normalize_*`, `get_running_config`, `build_commands` directly + +3. Add integration target: `tests/integration/targets/<module>/tasks/main.yaml` + - Follow the teardown → merged → idempotent → gathered → replaced → deleted pattern + +## Key Differences from CLI Collection Tests + +| CLI collection | REST collection | +|---|---| +| Mocks `connection.get` returning CLI text | Mocks `vyos.get_config()` returning JSON dict | +| Fixture files are `.cfg` text (CLI output) | Fixture files are `.json` (API response) | +| Tests parse CLI text via `rm_templates` | Tests parse API dicts via `normalize_running` | +| `ansible-test units --docker` for isolation | Can run with `pytest` directly, no docker needed | diff --git a/tests/integration/network-integration.cfg b/tests/integration/network-integration.cfg new file mode 100644 index 0000000..d12c1ef --- /dev/null +++ b/tests/integration/network-integration.cfg @@ -0,0 +1,4 @@ +[persistent_connection] +command_timeout = 100 +connect_timeout = 100 +connect_retry_timeout = 100 diff --git a/tests/integration/targets/prepare_vyos_tests/meta/main.yaml b/tests/integration/targets/prepare_vyos_tests/meta/main.yaml new file mode 100644 index 0000000..61d3ffe --- /dev/null +++ b/tests/integration/targets/prepare_vyos_tests/meta/main.yaml @@ -0,0 +1,2 @@ +--- +allow_duplicates: true diff --git a/tests/integration/targets/prepare_vyos_tests/tasks/main.yaml b/tests/integration/targets/prepare_vyos_tests/tasks/main.yaml new file mode 100644 index 0000000..9527685 --- /dev/null +++ b/tests/integration/targets/prepare_vyos_tests/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Add dummy loopback address for SNMP listen test + vyos.rest.vyos_configure: + commands: + - set interfaces loopback lo address 20.1.1.1/32 diff --git a/tests/integration/targets/vyos_banner/aliases b/tests/integration/targets/vyos_banner/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_banner/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_banner/defaults/main.yaml b/tests/integration/targets/vyos_banner/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_banner/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_banner/tasks/httpapi.yaml b/tests/integration/targets/vyos_banner/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_banner/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_banner/tasks/main.yaml b/tests/integration/targets/vyos_banner/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_banner/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_banner/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_banner/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..7bd2698 --- /dev/null +++ b/tests/integration/targets/vyos_banner/tests/httpapi/_populate_config.yaml @@ -0,0 +1,14 @@ +--- +- name: Populate pre-login banner for testing + vyos.rest.vyos_banner: + config: + banner: pre-login + text: "Ansible test pre-login banner" + state: merged + +- name: Populate post-login banner for testing + vyos.rest.vyos_banner: + config: + banner: post-login + text: "Ansible test post-login banner" + state: merged diff --git a/tests/integration/targets/vyos_banner/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_banner/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..2b43847 --- /dev/null +++ b/tests/integration/targets/vyos_banner/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove all banners + vyos.rest.vyos_banner: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_banner/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_banner/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..82e0f6e --- /dev/null +++ b/tests/integration/targets/vyos_banner/tests/httpapi/deleted.yaml @@ -0,0 +1,30 @@ +--- +- debug: + msg: START vyos_banner deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete pre-login banner + register: result + vyos.rest.vyos_banner: &id001 + config: + banner: pre-login + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete pre-login banner (IDEMPOTENT) + register: result + vyos.rest.vyos_banner: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_banner/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_banner/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..a51ff48 --- /dev/null +++ b/tests/integration/targets/vyos_banner/tests/httpapi/gathered.yaml @@ -0,0 +1,20 @@ +--- +- debug: + msg: START vyos_banner gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather banner configuration + register: result + vyos.rest.vyos_banner: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered is defined + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_banner/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_banner/tests/httpapi/merged.yaml new file mode 100644 index 0000000..96a984e --- /dev/null +++ b/tests/integration/targets/vyos_banner/tests/httpapi/merged.yaml @@ -0,0 +1,34 @@ +--- +- debug: + msg: START vyos_banner gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather all banners (no config specified) + register: result + vyos.rest.vyos_banner: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered is defined + - "'pre-login' in result.gathered" + - "'post-login' in result.gathered" + + - name: Gather specific pre-login banner + register: result + vyos.rest.vyos_banner: + config: + banner: pre-login + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered.text == "Ansible test pre-login banner" + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_banner/vars/main.yaml b/tests/integration/targets/vyos_banner/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_banner/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_configure/aliases b/tests/integration/targets/vyos_configure/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_configure/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_configure/defaults/main.yaml b/tests/integration/targets/vyos_configure/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_configure/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_configure/tasks/httpapi.yaml b/tests/integration/targets/vyos_configure/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_configure/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_configure/tasks/main.yaml b/tests/integration/targets/vyos_configure/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_configure/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_configure/tests/httpapi/configure.yaml b/tests/integration/targets/vyos_configure/tests/httpapi/configure.yaml new file mode 100644 index 0000000..2f95df3 --- /dev/null +++ b/tests/integration/targets/vyos_configure/tests/httpapi/configure.yaml @@ -0,0 +1,52 @@ +--- +- debug: + msg: START vyos_configure integration tests on connection={{ ansible_connection }} + +- block: + - name: Set a loopback address via vyos_configure + register: result + vyos.rest.vyos_configure: + commands: + - set interfaces loopback lo address 192.0.2.100/32 + + - assert: + that: + - result.changed == true + - result.commands | length == 1 + - result.commands[0][0] == "set" + - result.commands[0][1] == ["interfaces", "loopback", "lo", "address", "192.0.2.100/32"] + + - name: Set multiple commands in one atomic commit + register: result + vyos.rest.vyos_configure: + commands: + - set interfaces loopback lo address 192.0.2.101/32 + - set interfaces loopback lo address 192.0.2.102/32 + + - assert: + that: + - result.changed == true + - result.commands | length == 2 + + - name: Delete loopback addresses + register: result + vyos.rest.vyos_configure: + commands: + - delete interfaces loopback lo address 192.0.2.100/32 + - delete interfaces loopback lo address 192.0.2.101/32 + - delete interfaces loopback lo address 192.0.2.102/32 + + - assert: + that: + - result.changed == true + - result.commands | length == 3 + - result.commands[0][0] == "delete" + + always: + - name: Cleanup — remove test loopback addresses + vyos.rest.vyos_configure: + commands: + - delete interfaces loopback lo address 192.0.2.100/32 + - delete interfaces loopback lo address 192.0.2.101/32 + - delete interfaces loopback lo address 192.0.2.102/32 + ignore_errors: true diff --git a/tests/integration/targets/vyos_configure/vars/main.yaml b/tests/integration/targets/vyos_configure/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_configure/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_hostname/aliases b/tests/integration/targets/vyos_hostname/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_hostname/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_hostname/defaults/main.yaml b/tests/integration/targets/vyos_hostname/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_hostname/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_hostname/tasks/httpapi.yaml b/tests/integration/targets/vyos_hostname/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_hostname/tasks/main.yaml b/tests/integration/targets/vyos_hostname/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_hostname/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_hostname/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..c6d2583 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/httpapi/_populate_config.yaml @@ -0,0 +1,6 @@ +--- +- name: Populate hostname for testing + vyos.rest.vyos_hostname: + config: + hostname: ansible-test-host + state: merged diff --git a/tests/integration/targets/vyos_hostname/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_hostname/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..a6f7aeb --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/httpapi/_remove_config.yaml @@ -0,0 +1,7 @@ +--- +- name: Reset hostname to default + vyos.rest.vyos_hostname: + config: + hostname: vyos + state: merged + ignore_errors: true diff --git a/tests/integration/targets/vyos_hostname/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_hostname/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..dfc8896 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/httpapi/gathered.yaml @@ -0,0 +1,19 @@ +--- +- debug: + msg: START vyos_hostname gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _populate_config.yaml + +- block: + - name: Gather hostname configuration + register: result + vyos.rest.vyos_hostname: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered.hostname == "ansible-test-host" + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_hostname/tests/httpapi/merged.yaml new file mode 100644 index 0000000..d815d53 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/httpapi/merged.yaml @@ -0,0 +1,30 @@ +--- +- debug: + msg: START vyos_hostname merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge hostname configuration + register: result + vyos.rest.vyos_hostname: &id001 + config: + hostname: ansible-test-host + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge hostname configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_hostname: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_hostname/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..b4e318d --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/httpapi/replaced.yaml @@ -0,0 +1,30 @@ +--- +- debug: + msg: START vyos_hostname replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _populate_config.yaml + +- block: + - name: Replace hostname configuration + register: result + vyos.rest.vyos_hostname: &id001 + config: + hostname: ansible-replaced-host + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace hostname configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_hostname: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/vars/main.yaml b/tests/integration/targets/vyos_hostname/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_lldp_global/aliases b/tests/integration/targets/vyos_lldp_global/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_lldp_global/defaults/main.yaml b/tests/integration/targets/vyos_lldp_global/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_lldp_global/tasks/httpapi.yaml b/tests/integration/targets/vyos_lldp_global/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_lldp_global/tasks/main.yaml b/tests/integration/targets/vyos_lldp_global/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..6c3acf4 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/_populate_config.yaml @@ -0,0 +1,20 @@ +--- +- name: Configure SNMP first (required for LLDP snmp) + vyos.rest.vyos_snmp_server: + config: + communities: + - name: lldp-test + authorization_type: ro + state: merged + +- name: Populate lldp_global config for testing + vyos.rest.vyos_lldp_global: + config: + enable: true + addresses: + - 192.0.2.17 + snmp: enable + legacy_protocols: + - cdp + - sonmp + state: merged diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..9e3b01d --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove pre-existing lldp_global config + vyos.rest.vyos_lldp_global: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..d084d4a --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/deleted.yaml @@ -0,0 +1,28 @@ +--- +- debug: + msg: START vyos_lldp_global deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all lldp_global configuration + register: result + vyos.rest.vyos_lldp_global: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete lldp_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_lldp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..20ac2b2 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/gathered.yaml @@ -0,0 +1,20 @@ +--- +- debug: + msg: START vyos_lldp_global gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather lldp_global configuration + register: result + vyos.rest.vyos_lldp_global: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered is defined + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/merged.yaml new file mode 100644 index 0000000..a4c9bec --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/merged.yaml @@ -0,0 +1,36 @@ +--- +- debug: + msg: START vyos_lldp_global merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge lldp_global configuration + register: result + vyos.rest.vyos_lldp_global: &id001 + config: + enable: true + addresses: + - 192.0.2.17 + snmp: enable + legacy_protocols: + - cdp + - sonmp + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge lldp_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_lldp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_global/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_lldp_global/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..d5523eb --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/tests/httpapi/replaced.yaml @@ -0,0 +1,35 @@ +--- +- debug: + msg: START vyos_lldp_global replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Replace lldp_global configuration + register: result + vyos.rest.vyos_lldp_global: &id001 + config: + enable: true + addresses: + - 192.0.2.99 + legacy_protocols: + - cdp + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace lldp_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_lldp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_global/vars/main.yaml b/tests/integration/targets/vyos_lldp_global/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_logging_global/aliases b/tests/integration/targets/vyos_logging_global/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_logging_global/defaults/main.yaml b/tests/integration/targets/vyos_logging_global/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_logging_global/tasks/httpapi.yaml b/tests/integration/targets/vyos_logging_global/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_logging_global/tasks/main.yaml b/tests/integration/targets/vyos_logging_global/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..c081853 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/_populate_config.yaml @@ -0,0 +1,21 @@ +--- +- name: Populate logging_global config for testing + vyos.rest.vyos_logging_global: + config: + console: + facilities: + - facility: local7 + severity: err + hosts: + - hostname: 172.16.0.1 + port: 514 + facilities: + - facility: local7 + severity: all + global_params: + facilities: + - facility: cron + severity: debug + preserve_fqdn: true + state: merged + ignore_errors: true diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..14975a5 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove pre-existing logging_global config + vyos.rest.vyos_logging_global: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..8c62627 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/deleted.yaml @@ -0,0 +1,28 @@ +--- +- debug: + msg: START vyos_logging_global deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all logging_global configuration + register: result + vyos.rest.vyos_logging_global: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete logging_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_logging_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..667c088 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/gathered.yaml @@ -0,0 +1,20 @@ +--- +- debug: + msg: START vyos_logging_global gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather logging_global configuration + register: result + vyos.rest.vyos_logging_global: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered is defined + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/merged.yaml new file mode 100644 index 0000000..daa1c2a --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/merged.yaml @@ -0,0 +1,44 @@ +--- +- debug: + msg: START vyos_logging_global merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge logging_global configuration + register: result + vyos.rest.vyos_logging_global: &id001 + config: + console: + facilities: + - facility: local7 + severity: err + hosts: + - hostname: 172.16.0.1 + port: 514 + facilities: + - facility: local7 + severity: all + global_params: + facilities: + - facility: cron + severity: debug + preserve_fqdn: true + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge logging_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_logging_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_logging_global/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_logging_global/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..a1c24c0 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/tests/httpapi/replaced.yaml @@ -0,0 +1,33 @@ +--- +- debug: + msg: START vyos_logging_global replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Replace logging_global configuration + register: result + vyos.rest.vyos_logging_global: &id001 + config: + console: + facilities: + - facility: local6 + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace logging_global configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_logging_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_logging_global/vars/main.yaml b/tests/integration/targets/vyos_logging_global/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_logging_global/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_ntp_global/aliases b/tests/integration/targets/vyos_ntp_global/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_ntp_global/defaults/main.yaml b/tests/integration/targets/vyos_ntp_global/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_ntp_global/tasks/httpapi.yaml b/tests/integration/targets/vyos_ntp_global/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_ntp_global/tasks/main.yaml b/tests/integration/targets/vyos_ntp_global/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..aac01d9 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/_populate_config.yaml @@ -0,0 +1,21 @@ +--- +- name: Populate NTP config for testing + vyos.rest.vyos_ntp_global: + config: + allow_clients: + - 10.4.9.0/24 + - 10.4.7.0/24 + listen_addresses: + - 10.1.9.16 + servers: + - server: 10.3.6.5 + options: + - noselect + - prefer + - server: server4.example.com + options: + - pool + - noselect + - server: server5.example.com + state: merged + ignore_errors: true diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..4355886 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove pre-existing ntp_global config + vyos.rest.vyos_ntp_global: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..957e119 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/deleted.yaml @@ -0,0 +1,35 @@ +--- +- debug: + msg: START vyos_ntp_global deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all NTP configuration + register: result + vyos.rest.vyos_ntp_global: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Assert after is empty + assert: + that: + - result.after.allow_clients == [] + - result.after.listen_addresses == [] + - result.after.servers == {} + + - name: Delete the existing configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_ntp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..73ee1ff --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/gathered.yaml @@ -0,0 +1,23 @@ +--- +- debug: + msg: START vyos_ntp_global gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather NTP configuration + register: result + vyos.rest.vyos_ntp_global: + state: gathered + + - assert: + that: + - result.changed == false + - "'10.4.9.0/24' in result.gathered.allow_clients" + - "'10.1.9.16' in result.gathered.listen_addresses" + - "'10.3.6.5' in result.gathered.servers" + - "'server4.example.com' in result.gathered.servers" + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/merged.yaml new file mode 100644 index 0000000..613704a --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/merged.yaml @@ -0,0 +1,38 @@ +--- +- debug: + msg: START vyos_ntp_global merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge the provided configuration with the existing running configuration + register: result + vyos.rest.vyos_ntp_global: &id001 + config: + allow_clients: + - 10.6.6.0/24 + listen_addresses: + - 10.1.3.1 + servers: + - server: 203.0.113.0 + options: + - prefer + state: merged + + - assert: + that: + - result.changed == true + - result.commands | length > 0 + + - name: Merge the provided configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_ntp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/overridden.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/overridden.yaml new file mode 100644 index 0000000..deee2c0 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/overridden.yaml @@ -0,0 +1,41 @@ +--- +- debug: + msg: START vyos_ntp_global overridden integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Override the existing configuration with the provided configuration + register: result + vyos.rest.vyos_ntp_global: &id001 + config: + allow_clients: + - 10.3.3.0/24 + listen_addresses: + - 10.7.8.1 + servers: + - server: server1 + options: + - prefer + - server: server2 + options: + - noselect + state: overridden + + - assert: + that: + - result.changed == true + + - name: Override the provided configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_ntp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ntp_global/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_ntp_global/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..77136fc --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/tests/httpapi/replaced.yaml @@ -0,0 +1,48 @@ +--- +- debug: + msg: START vyos_ntp_global replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Replace the existing configuration with the provided configuration + register: result + vyos.rest.vyos_ntp_global: &id001 + config: + allow_clients: + - 10.99.99.0/24 + servers: + - server: server-new.example.com + options: + - prefer + state: replaced + + - assert: + that: + - result.changed == true + + - name: Verify old entries removed + vyos.rest.vyos_ntp_global: + state: gathered + register: gathered + + - assert: + that: + - "'10.4.9.0/24' not in gathered.gathered.allow_clients" + - "'10.99.99.0/24' in gathered.gathered.allow_clients" + - "'server-new.example.com' in gathered.gathered.servers" + - "'10.3.6.5' not in gathered.gathered.servers" + + - name: Replace the provided configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_ntp_global: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ntp_global/vars/main.yaml b/tests/integration/targets/vyos_ntp_global/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_ntp_global/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_prefix_lists/aliases b/tests/integration/targets/vyos_prefix_lists/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_prefix_lists/defaults/main.yaml b/tests/integration/targets/vyos_prefix_lists/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_prefix_lists/tasks/httpapi.yaml b/tests/integration/targets/vyos_prefix_lists/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_prefix_lists/tasks/main.yaml b/tests/integration/targets/vyos_prefix_lists/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_deleted.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_deleted.yaml new file mode 100644 index 0000000..6cfb063 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_deleted.yaml @@ -0,0 +1,28 @@ +--- +- debug: + msg: START vyos_prefix_lists deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all prefix_lists configuration + register: result + vyos.rest.vyos_prefix_lists: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete prefix_lists configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_prefix_lists: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_gathered.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_gathered.yaml new file mode 100644 index 0000000..083cb48 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_gathered.yaml @@ -0,0 +1,20 @@ +--- +- debug: + msg: START vyos_prefix_lists gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather prefix_lists configuration + register: result + vyos.rest.vyos_prefix_lists: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered | selectattr('afi','eq','ipv4') | list | length > 0 + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_merged.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_merged.yaml new file mode 100644 index 0000000..a70f826 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_merged.yaml @@ -0,0 +1,42 @@ +--- +- debug: + msg: START vyos_prefix_lists merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge prefix_lists configuration + register: result + vyos.rest.vyos_prefix_lists: &id001 + config: + - afi: ipv4 + prefix_lists: + - name: AnsibleIPv4PrefixList + description: PL configured by ansible + entries: + - sequence: 2 + action: permit + prefix: 92.168.10.0/26 + le: 32 + - sequence: 3 + action: deny + prefix: 72.168.2.0/24 + ge: 26 + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge prefix_lists configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_prefix_lists: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..9d73f0b --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_populate_config.yaml @@ -0,0 +1,28 @@ +--- +- name: Populate prefix_lists config for testing + vyos.rest.vyos_prefix_lists: + config: + - afi: ipv4 + prefix_lists: + - name: AnsibleIPv4PrefixList + description: PL configured by ansible + entries: + - sequence: 2 + action: permit + prefix: 92.168.10.0/26 + le: 32 + - sequence: 3 + action: deny + prefix: 72.168.2.0/24 + ge: 26 + - afi: ipv6 + prefix_lists: + - name: AllowIPv6Prefix + description: Configured by ansible for allowing IPv6 networks + entries: + - sequence: 5 + action: permit + prefix: 2001:db8:8000::/35 + le: 37 + state: merged + ignore_errors: true diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..043fb3e --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove pre-existing prefix_lists config + vyos.rest.vyos_prefix_lists: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_replaced.yaml b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_replaced.yaml new file mode 100644 index 0000000..bd8c5c1 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/tests/httpapi/_replaced.yaml @@ -0,0 +1,37 @@ +--- +- debug: + msg: START vyos_prefix_lists replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Replace prefix_lists configuration + register: result + vyos.rest.vyos_prefix_lists: &id001 + config: + - afi: ipv4 + prefix_lists: + - name: AnsibleIPv4PrefixList + entries: + - sequence: 10 + action: permit + prefix: 10.0.0.0/8 + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace prefix_lists configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_prefix_lists: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_prefix_lists/vars/main.yaml b/tests/integration/targets/vyos_prefix_lists/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_prefix_lists/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_route_maps/aliases b/tests/integration/targets/vyos_route_maps/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_route_maps/defaults/main.yaml b/tests/integration/targets/vyos_route_maps/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_route_maps/tasks/httpapi.yaml b/tests/integration/targets/vyos_route_maps/tasks/httpapi.yaml new file mode 100644 index 0000000..4147e6d --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tasks/httpapi.yaml @@ -0,0 +1,21 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_route_maps/tasks/main.yaml b/tests/integration/targets/vyos_route_maps/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..adcaf55 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/_populate_config.yaml @@ -0,0 +1,17 @@ +--- +- name: Populate route_maps config for testing + vyos.rest.vyos_route_maps: + config: + - route_map: RM-TEST-EXPORT-POLICY + entries: + - sequence: 10 + action: permit + match: + peer: 192.0.2.32 + set: + metric: "5" + as_path_exclude: "111" + aggregator: + as: 100 + state: merged + ignore_errors: true diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..de02f54 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove pre-existing route_maps config + vyos.rest.vyos_route_maps: + state: deleted + ignore_errors: true diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..ec80b23 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/deleted.yaml @@ -0,0 +1,28 @@ +--- +- debug: + msg: START vyos_route_maps deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all route_maps configuration + register: result + vyos.rest.vyos_route_maps: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete route_maps configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_route_maps: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..494a23e --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/gathered.yaml @@ -0,0 +1,20 @@ +--- +- debug: + msg: START vyos_route_maps gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Gather route_maps configuration + register: result + vyos.rest.vyos_route_maps: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered | selectattr('route_map','eq','RM-TEST-EXPORT-POLICY') | list | length == 1 + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/merged.yaml new file mode 100644 index 0000000..c8c9474 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/merged.yaml @@ -0,0 +1,40 @@ +--- +- debug: + msg: START vyos_route_maps merged integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge route_maps configuration + register: result + vyos.rest.vyos_route_maps: &id001 + config: + - route_map: RM-TEST-EXPORT-POLICY + entries: + - sequence: 10 + action: permit + match: + peer: 192.0.2.32 + set: + metric: "5" + as_path_exclude: "111" + aggregator: + as: 100 + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge route_maps configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_route_maps: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_route_maps/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_route_maps/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..dece9a8 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/tests/httpapi/replaced.yaml @@ -0,0 +1,36 @@ +--- +- debug: + msg: START vyos_route_maps replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _remove_config.yaml +- include_tasks: _populate_config.yaml + +- block: + - name: Replace route_maps configuration + register: result + vyos.rest.vyos_route_maps: &id001 + config: + - route_map: RM-TEST-EXPORT-POLICY + entries: + - sequence: 10 + action: permit + set: + metric: "10" + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace route_maps configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_route_maps: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_route_maps/vars/main.yaml b/tests/integration/targets/vyos_route_maps/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_route_maps/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/integration/targets/vyos_snmp_server/aliases b/tests/integration/targets/vyos_snmp_server/aliases new file mode 100644 index 0000000..cc0afef --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/aliases @@ -0,0 +1 @@ +network/vyos diff --git a/tests/integration/targets/vyos_snmp_server/defaults/main.yaml b/tests/integration/targets/vyos_snmp_server/defaults/main.yaml new file mode 100644 index 0000000..164afea --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/vyos_snmp_server/meta/main.yaml b/tests/integration/targets/vyos_snmp_server/meta/main.yaml new file mode 100644 index 0000000..7413320 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: + - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_snmp_server/tasks/cleanup.yaml b/tests/integration/targets/vyos_snmp_server/tasks/cleanup.yaml new file mode 100644 index 0000000..d861c1b --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tasks/cleanup.yaml @@ -0,0 +1,5 @@ +--- +- name: Remove dummy loopback address + vyos.rest.vyos_configure: + commands: + - delete interfaces loopback lo address 20.1.1.1/32 diff --git a/tests/integration/targets/vyos_snmp_server/tasks/httpapi.yaml b/tests/integration/targets/vyos_snmp_server/tasks/httpapi.yaml new file mode 100644 index 0000000..1ba3569 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tasks/httpapi.yaml @@ -0,0 +1,24 @@ +--- +- name: Collect all httpapi test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/httpapi" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=httpapi) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.httpapi + ansible_network_os: vyos.rest.vyos + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run + +- name: Post-test cleanup + ansible.builtin.include_tasks: cleanup.yaml diff --git a/tests/integration/targets/vyos_snmp_server/tasks/main.yaml b/tests/integration/targets/vyos_snmp_server/tasks/main.yaml new file mode 100644 index 0000000..b1f6193 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Run httpapi tests + ansible.builtin.include_tasks: httpapi.yaml + tags: + - httpapi diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/_populate_config.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/_populate_config.yaml new file mode 100644 index 0000000..d3762c1 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/_populate_config.yaml @@ -0,0 +1,16 @@ +--- +- ansible.builtin.include_tasks: _remove_config.yaml + +- name: Populate snmp_server config for testing + vyos.rest.vyos_snmp_server: + config: + communities: + - name: switches + authorization_type: rw + - name: bridges + clients: + - 1.1.1.1 + contact: admin@example.com + listen_addresses: + - address: 20.1.1.1 + state: merged diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/_remove_config.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/_remove_config.yaml new file mode 100644 index 0000000..e954df7 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/_remove_config.yaml @@ -0,0 +1,5 @@ +# _remove_config.yaml +--- +- name: Remove pre-existing snmp_server config + vyos.rest.vyos_snmp_server: + state: deleted diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/deleted.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/deleted.yaml new file mode 100644 index 0000000..a626a26 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/deleted.yaml @@ -0,0 +1,27 @@ +--- +- debug: + msg: START vyos_snmp_server deleted integration tests on connection={{ ansible_connection }} + +- include_tasks: _populate_config.yaml + +- block: + - name: Delete all snmp_server configuration + register: result + vyos.rest.vyos_snmp_server: &id001 + state: deleted + + - assert: + that: + - result.changed == true + + - name: Delete snmp_server configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_snmp_server: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/gathered.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/gathered.yaml new file mode 100644 index 0000000..770845c --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/gathered.yaml @@ -0,0 +1,19 @@ +--- +- debug: + msg: START vyos_snmp_server gathered integration tests on connection={{ ansible_connection }} + +- include_tasks: _populate_config.yaml + +- block: + - name: Gather snmp_server configuration + register: result + vyos.rest.vyos_snmp_server: + state: gathered + + - assert: + that: + - result.changed == false + - result.gathered is defined + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/merged.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/merged.yaml new file mode 100644 index 0000000..e1c6531 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/merged.yaml @@ -0,0 +1,36 @@ +--- +- debug: + msg: START vyos_snmp_server merged integration tests on connection={{ ansible_connection }} + +- block: + - name: Merge snmp_server configuration + register: result + vyos.rest.vyos_snmp_server: &id001 + config: + communities: + - name: switches + authorization_type: rw + - name: bridges + clients: + - 1.1.1.1 + contact: admin@example.com + listen_addresses: + - address: 20.1.1.1 + state: merged + + - assert: + that: + - result.changed == true + + - name: Merge snmp_server configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_snmp_server: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_snmp_server/tests/httpapi/replaced.yaml b/tests/integration/targets/vyos_snmp_server/tests/httpapi/replaced.yaml new file mode 100644 index 0000000..d989272 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/tests/httpapi/replaced.yaml @@ -0,0 +1,33 @@ +--- +- debug: + msg: START vyos_snmp_server replaced integration tests on connection={{ ansible_connection }} + +- include_tasks: _populate_config.yaml + +- block: + - name: Replace snmp_server configuration + register: result + vyos.rest.vyos_snmp_server: &id001 + config: + communities: + - name: routers + authorization_type: ro + location: "RDU, NC" + state: replaced + + - assert: + that: + - result.changed == true + + - name: Replace snmp_server configuration (IDEMPOTENT) + register: result + vyos.rest.vyos_snmp_server: *id001 + + - name: Assert idempotent + assert: + that: + - result.changed == false + - result.commands == [] + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_snmp_server/vars/main.yaml b/tests/integration/targets/vyos_snmp_server/vars/main.yaml new file mode 100644 index 0000000..4303881 --- /dev/null +++ b/tests/integration/targets/vyos_snmp_server/vars/main.yaml @@ -0,0 +1,2 @@ +--- +# only common vars here diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/unit/__init__.py diff --git a/tests/unit/fixtures/lldp_global_running.json b/tests/unit/fixtures/lldp_global_running.json new file mode 100644 index 0000000..fdd6aa4 --- /dev/null +++ b/tests/unit/fixtures/lldp_global_running.json @@ -0,0 +1,10 @@ +{ + "management-address": { + "192.0.2.17": {} + }, + "snmp": {}, + "legacy-protocols": { + "cdp": {}, + "sonmp": {} + } +} diff --git a/tests/unit/fixtures/logging_global_running.json b/tests/unit/fixtures/logging_global_running.json new file mode 100644 index 0000000..557408d --- /dev/null +++ b/tests/unit/fixtures/logging_global_running.json @@ -0,0 +1,42 @@ +{ + "console": { + "facility": { + "all": {}, + "local7": { "level": "err" } + } + }, + "file": { + "logFile": { + "archive": { "file": "2" }, + "facility": { + "local6": { "level": "emerg" } + } + } + }, + "global": { + "archive": { "file": "2", "size": "111" }, + "facility": { + "cron": { "level": "debug" }, + "all": { "level": "info" }, + "local7": { "level": "debug" } + }, + "marker": { "interval": "111" }, + "preserve-fqdn": {} + }, + "host": { + "172.16.0.1": { + "facility": { + "local7": { "level": "all" }, + "all": { "protocol": "udp" } + }, + "port": "223" + } + }, + "user": { + "vyos": { + "facility": { + "local7": { "level": "debug" } + } + } + } +} diff --git a/tests/unit/fixtures/ntp_global_running.json b/tests/unit/fixtures/ntp_global_running.json new file mode 100644 index 0000000..95a9ff8 --- /dev/null +++ b/tests/unit/fixtures/ntp_global_running.json @@ -0,0 +1,17 @@ +{ + "allow-client": { + "address": { + "10.6.6.0/24": {} + } + }, + "listen-address": { + "10.1.3.1": {} + }, + "server": { + "time1.vyos.net": {}, + "time2.vyos.net": {}, + "203.0.113.0": { + "prefer": {} + } + } +} diff --git a/tests/unit/fixtures/prefix_lists_running.json b/tests/unit/fixtures/prefix_lists_running.json new file mode 100644 index 0000000..2a6ecd3 --- /dev/null +++ b/tests/unit/fixtures/prefix_lists_running.json @@ -0,0 +1,44 @@ +{ + "prefix-list": { + "AnsibleIPv4PrefixList": { + "description": "PL configured by ansible", + "rule": { + "2": { + "action": "permit", + "prefix": "92.168.10.0/26", + "le": "32", + "description": "Rule 2 given by ansible" + }, + "3": { + "action": "deny", + "prefix": "72.168.2.0/24", + "ge": "26", + "description": "Rule 3" + } + } + } + }, + "prefix-list6": { + "AllowIPv6Prefix": { + "description": "Configured by ansible for allowing IPv6 networks", + "rule": { + "5": { + "action": "permit", + "prefix": "2001:db8:8000::/35", + "le": "37", + "description": "Permit rule" + } + } + }, + "DenyIPv6Prefix": { + "description": "Configured by ansible for disallowing IPv6 networks", + "rule": { + "8": { + "action": "deny", + "prefix": "2001:db8:2000::/35", + "le": "37" + } + } + } + } +} diff --git a/tests/unit/fixtures/route_maps_running.json b/tests/unit/fixtures/route_maps_running.json new file mode 100644 index 0000000..acf733b --- /dev/null +++ b/tests/unit/fixtures/route_maps_running.json @@ -0,0 +1,31 @@ +{ + "route-map": { + "RM-TEST-EXPORT-POLICY": { + "rule": { + "10": { + "action": "permit", + "match": { "peer": "192.0.2.32" }, + "set": { + "aggregator": { "as": "100" }, + "as-path": { "exclude": "111" }, + "metric": "5" + } + } + } + }, + "rm1": { + "rule": { + "10": { + "action": "permit", + "match": { "peer": "192.0.2.32" }, + "set": { + "aggregator": { "as": "100" }, + "as-path": { "exclude": "111" }, + "large-community": { "none": {} }, + "metric": "5" + } + } + } + } + } +} diff --git a/tests/unit/fixtures/snmp_server_running.json b/tests/unit/fixtures/snmp_server_running.json new file mode 100644 index 0000000..7acc59f --- /dev/null +++ b/tests/unit/fixtures/snmp_server_running.json @@ -0,0 +1,35 @@ +{ + "community": { + "switches": { "authorization": "rw" }, + "bridges": { + "client": ["1.1.1.1", "12.1.1.10"] + } + }, + "contact": "admin@example.com", + "listen-address": { + "20.1.1.1": {}, + "100.1.2.1": { "port": "33" } + }, + "v3": { + "engineid": "000000000000000000000002", + "group": { + "default": { "mode": "ro", "view": "default" } + }, + "user": { + "admin_user": { + "auth": { + "encrypted-password": "abc123", + "type": "sha" + }, + "privacy": { + "encrypted-password": "abc123", + "type": "aes" + }, + "group": "default" + } + }, + "view": { + "default": { "oid": { "1": {} } } + } + } +} diff --git a/tests/unit/modules/__init__.py b/tests/unit/modules/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/unit/modules/__init__.py diff --git a/tests/unit/modules/base.py b/tests/unit/modules/base.py new file mode 100644 index 0000000..4d49fbb --- /dev/null +++ b/tests/unit/modules/base.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# GNU General Public License v3.0+ + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import json +import os +import unittest + +from unittest.mock import MagicMock # noqa: F401 + + +def load_fixture(filename): + """Load a JSON fixture file from tests/unit/fixtures/.""" + fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures") + path = os.path.join(fixtures_dir, filename) + with open(path) as f: + return json.load(f) + + +class VyOSModuleTestCase(unittest.TestCase): + """ + Base class for vyos.rest module unit tests. + + Provides a mock VyOSModule that returns fixture data from + get_config() without any device connection. + + Usage: + class TestVyOSNtpGlobal(VyOSModuleTestCase): + def setUp(self): + super().setUp() + self.fixture = load_fixture("ntp_global_running.json") + + def test_merged_adds_new_server(self): + have = self.module.get_running_config_from_fixture(self.fixture) + commands = build_commands(want, have, "merged") + self.assertIn(("set", ["service", "ntp", "server", "1.2.3.4"]), commands) + """ + + def setUp(self): + self.mock_module = MagicMock() + self.mock_module.params = {} + self.mock_module.check_mode = False + + self.mock_vyos = MagicMock() + self.mock_vyos.get_config = MagicMock(return_value={}) + + def set_running_config(self, data): + """Configure mock get_config to return given data.""" + self.mock_vyos.get_config.return_value = data diff --git a/tests/unit/modules/conftest.py b/tests/unit/modules/conftest.py new file mode 100644 index 0000000..26b7d8b --- /dev/null +++ b/tests/unit/modules/conftest.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# conftest.py — shared fixtures for vyos.rest unit tests diff --git a/tests/unit/modules/test_vyos_configure.py b/tests/unit/modules/test_vyos_configure.py new file mode 100644 index 0000000..af1b325 --- /dev/null +++ b/tests/unit/modules/test_vyos_configure.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import unittest + +from ansible_collections.vyos.rest.plugins.modules.vyos_configure import ( + _parse_command, +) + + +class TestVyOSConfigureParseCommand(unittest.TestCase): + + def test_set_simple(self): + result = _parse_command("set system host-name vyos") + self.assertEqual(result, ("set", ["system", "host-name", "vyos"])) + + def test_set_with_address(self): + result = _parse_command("set interfaces loopback lo address 20.1.1.1/32") + self.assertEqual( + result, + ("set", ["interfaces", "loopback", "lo", "address", "20.1.1.1/32"]), + ) + + def test_delete_simple(self): + result = _parse_command("delete service snmp") + self.assertEqual(result, ("delete", ["service", "snmp"])) + + def test_delete_with_path(self): + result = _parse_command("delete interfaces loopback lo address 20.1.1.1/32") + self.assertEqual( + result, + ("delete", ["interfaces", "loopback", "lo", "address", "20.1.1.1/32"]), + ) + + def test_strips_leading_whitespace(self): + result = _parse_command(" set system host-name vyos") + self.assertEqual(result, ("set", ["system", "host-name", "vyos"])) + + def test_invalid_command_returns_none(self): + result = _parse_command("commit") + self.assertIsNone(result) + + def test_empty_string_returns_none(self): + result = _parse_command("") + self.assertIsNone(result) + + def test_unknown_op_returns_none(self): + result = _parse_command("show interfaces") + self.assertIsNone(result) + + def test_set_single_token_path(self): + result = _parse_command("set service") + self.assertEqual(result, ("set", ["service"])) + + def test_delete_single_token_path(self): + result = _parse_command("delete service") + self.assertEqual(result, ("delete", ["service"])) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/modules/test_vyos_logging_global.py b/tests/unit/modules/test_vyos_logging_global.py new file mode 100644 index 0000000..8593f1f --- /dev/null +++ b/tests/unit/modules/test_vyos_logging_global.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import os +import sys +import unittest + + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")) + +from ansible_collections.vyos.rest.plugins.modules.vyos_logging_global import ( + build_commands, + normalize_config, + normalize_running, +) + + +class TestVyOSLoggingGlobalNormalize(unittest.TestCase): + + def test_normalize_config_console_severity_is_string(self): + cfg = { + "console": { + "facilities": [{"facility": "local7", "severity": "err"}], + }, + } + result = normalize_config(cfg) + self.assertIn("local7", result["console"]["facilities"]) + # severity is stored as plain string, not dict + self.assertEqual(result["console"]["facilities"]["local7"], "err") + + def test_normalize_config_console_no_severity(self): + cfg = { + "console": { + "facilities": [{"facility": "all"}], + }, + } + result = normalize_config(cfg) + self.assertIsNone(result["console"]["facilities"]["all"]) + + def test_normalize_config_hosts(self): + cfg = { + "hosts": [ + { + "hostname": "172.16.0.1", + "port": 514, + "facilities": [ + {"facility": "local7", "severity": "all"}, + {"facility": "all", "protocol": "udp"}, + ], + }, + ], + } + result = normalize_config(cfg) + self.assertIn("172.16.0.1", result["hosts"]) + host = result["hosts"]["172.16.0.1"] + self.assertEqual(host["port"], 514) + self.assertIn("local7", host["facilities"]) + # host facilities are dicts with severity/protocol + self.assertEqual(host["facilities"]["local7"]["severity"], "all") + self.assertEqual(host["facilities"]["all"]["protocol"], "udp") + + def test_normalize_config_global_preserve_fqdn(self): + cfg = {"global_params": {"preserve_fqdn": True}} + result = normalize_config(cfg) + self.assertTrue(result["global"]["preserve_fqdn"]) + + def test_normalize_config_global_archive(self): + cfg = {"global_params": {"archive": {"file_num": 2, "size": 111}}} + result = normalize_config(cfg) + self.assertEqual(result["global"]["archive"]["file_num"], 2) + self.assertEqual(result["global"]["archive"]["size"], 111) + + def test_normalize_config_empty(self): + result = normalize_config({}) + self.assertEqual(result["console"]["facilities"], {}) + self.assertEqual(result["hosts"], {}) + self.assertEqual(result["files"], {}) + self.assertEqual(result["users"], {}) + + def test_normalize_running_console_severity_is_string(self): + raw = { + "console": { + "facility": { + "local7": {"level": "err"}, + "all": {}, + }, + }, + } + result = normalize_running(raw) + self.assertIn("local7", result["console"]["facilities"]) + # severity is plain string from "level" key + self.assertEqual(result["console"]["facilities"]["local7"], "err") + self.assertIsNone(result["console"]["facilities"]["all"]) + + def test_normalize_running_host_port_not_cast(self): + """Port is NOT cast to int — stored as-is from API response.""" + raw = { + "host": { + "172.16.0.1": { + "port": "514", + "facility": {}, + }, + }, + } + result = normalize_running(raw) + # port stays as string — module does not cast + self.assertEqual(result["hosts"]["172.16.0.1"]["port"], "514") + + def test_normalize_running_global_archive_key(self): + """Archive stored under 'archive' key — no file_num remapping.""" + raw = { + "global": { + "archive": {"file": "2", "size": "111"}, + "marker": {"interval": "111"}, + "preserve-fqdn": {}, + }, + } + result = normalize_running(raw) + # archive stored as-is from API + self.assertEqual(result["global"]["archive"]["file"], "2") + self.assertEqual(result["global"]["archive"]["size"], "111") + # marker_interval stored as string — no cast + self.assertEqual(result["global"]["marker_interval"], "111") + self.assertTrue(result["global"]["preserve_fqdn"]) + + def test_normalize_running_empty(self): + result = normalize_running({}) + self.assertEqual(result["console"]["facilities"], {}) + self.assertEqual(result["hosts"], {}) + + def test_normalize_running_host_facilities(self): + raw = { + "host": { + "172.16.0.1": { + "facility": { + "local7": {"level": "all"}, + "all": {"protocol": "udp"}, + }, + "port": "223", + }, + }, + } + result = normalize_running(raw) + h = result["hosts"]["172.16.0.1"] + self.assertEqual(h["facilities"]["local7"]["severity"], "all") + self.assertEqual(h["facilities"]["all"]["protocol"], "udp") + + +class TestVyOSLoggingGlobalBuildCommands(unittest.TestCase): + + def _empty_have(self): + return { + "console": {"facilities": {}}, + "global": {"facilities": {}}, + "hosts": {}, + "files": {}, + "users": {}, + } + + def test_merged_adds_console_facility_with_severity(self): + want = self._empty_have() + want["console"]["facilities"]["local7"] = "err" + cmds = build_commands(want, self._empty_have(), "merged") + self.assertIn( + ("set", ["system", "syslog", "console", "facility", "local7", "level", "err"]), + cmds, + ) + + def test_merged_adds_console_facility_no_severity(self): + want = self._empty_have() + want["console"]["facilities"]["all"] = None + cmds = build_commands(want, self._empty_have(), "merged") + self.assertIn( + ("set", ["system", "syslog", "console", "facility", "all"]), + cmds, + ) + + def test_merged_idempotent_console(self): + facs = {"local7": "err"} + want = self._empty_have() + have = self._empty_have() + want["console"]["facilities"] = facs + have["console"]["facilities"] = dict(facs) + cmds = build_commands(want, have, "merged") + self.assertEqual(cmds, []) + + def test_merged_adds_host(self): + want = self._empty_have() + want["hosts"]["172.16.0.1"] = { + "port": 514, + "facilities": {"local7": {"severity": "all", "protocol": None}}, + } + cmds = build_commands(want, self._empty_have(), "merged") + paths = [c[1] for c in cmds] + # diff_map only adds the host key, not per-facility details + self.assertIn(["system", "syslog", "host", "172.16.0.1"], paths) + + def test_replaced_removes_extra_host(self): + want = self._empty_have() + have = self._empty_have() + have["hosts"]["172.16.0.1"] = {"port": None, "facilities": {}} + cmds = build_commands(want, have, "replaced") + self.assertIn(("delete", ["system", "syslog", "host", "172.16.0.1"]), cmds) + + def test_deleted_removes_per_field(self): + """deleted state removes per-facility entries, not single subtree.""" + have = self._empty_have() + have["console"]["facilities"]["all"] = None + cmds = build_commands(self._empty_have(), have, "deleted") + self.assertIn( + ("delete", ["system", "syslog", "console", "facility", "all"]), + cmds, + ) + + def test_overridden_deletes_all_then_merges(self): + want = self._empty_have() + want["console"]["facilities"]["local7"] = "err" + have = self._empty_have() + have["console"]["facilities"]["all"] = None + cmds = build_commands(want, have, "overridden") + # first command is full syslog delete + self.assertEqual(cmds[0], ("delete", ["system", "syslog"])) + # then adds wanted facility + self.assertIn( + ("set", ["system", "syslog", "console", "facility", "local7", "level", "err"]), + cmds, + ) + + def test_no_commands_when_already_correct(self): + state = self._empty_have() + state["console"]["facilities"]["local7"] = "err" + cmds = build_commands(state, state, "merged") + self.assertEqual(cmds, []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/modules/test_vyos_ntp_global.py b/tests/unit/modules/test_vyos_ntp_global.py new file mode 100644 index 0000000..c536141 --- /dev/null +++ b/tests/unit/modules/test_vyos_ntp_global.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import json +import os +import unittest + +from unittest.mock import MagicMock + +from ansible_collections.vyos.rest.plugins.modules.vyos_ntp_global import ( + build_commands, + get_running_config, + normalize_config, + normalize_servers, +) + + +def load_fixture(filename): + fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures") + path = os.path.join(fixtures_dir, filename) + with open(path) as f: + return json.load(f) + + +class VyOSModuleTestCase(unittest.TestCase): + def setUp(self): + self.mock_vyos = MagicMock() + self.mock_vyos.get_config = MagicMock(return_value={}) + + def set_running_config(self, data): + self.mock_vyos.get_config.return_value = data + + +class TestVyOSNtpGlobalNormalize(unittest.TestCase): + """Test normalize_config and normalize_servers — no device needed.""" + + def test_normalize_config_empty(self): + result = normalize_config({}) + self.assertEqual(result["allow_clients"], []) + self.assertEqual(result["listen_addresses"], []) + self.assertEqual(result["servers"], {}) + + def test_normalize_config_servers_sorted(self): + config = { + "servers": [ + {"server": "b.example.com", "options": ["prefer", "noselect"]}, + {"server": "a.example.com"}, + ], + } + result = normalize_config(config) + self.assertIn("a.example.com", result["servers"]) + self.assertIn("b.example.com", result["servers"]) + self.assertEqual(result["servers"]["b.example.com"], ["noselect", "prefer"]) + + def test_normalize_servers_dict_with_options(self): + raw = { + "time1.vyos.net": {}, + "203.0.113.0": {"prefer": {}}, + } + result = normalize_servers(raw) + self.assertEqual(result["time1.vyos.net"], []) + self.assertEqual(result["203.0.113.0"], ["prefer"]) + + def test_normalize_servers_list(self): + raw = ["time1.vyos.net", "time2.vyos.net"] + result = normalize_servers(raw) + self.assertEqual(result["time1.vyos.net"], []) + + def test_normalize_servers_string(self): + result = normalize_servers("time1.vyos.net") + self.assertEqual(result["time1.vyos.net"], []) + + +class TestVyOSNtpGlobalGetRunning(VyOSModuleTestCase): + """Test get_running_config parsing against fixture API responses.""" + + def setUp(self): + super().setUp() + self.fixture = load_fixture("ntp_global_running.json") + + def test_parses_allow_clients(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + self.assertIn("10.6.6.0/24", result["allow_clients"]) + + def test_parses_listen_addresses(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + self.assertIn("10.1.3.1", result["listen_addresses"]) + + def test_parses_servers(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + self.assertIn("time1.vyos.net", result["servers"]) + self.assertIn("203.0.113.0", result["servers"]) + self.assertIn("prefer", result["servers"]["203.0.113.0"]) + + def test_empty_config_returns_empty(self): + self.set_running_config({}) + result = get_running_config(self.mock_vyos) + self.assertEqual(result["allow_clients"], []) + self.assertEqual(result["servers"], {}) + + +class TestVyOSNtpGlobalBuildCommands(unittest.TestCase): + """Test build_commands diff logic — no device needed.""" + + def _have(self, **kwargs): + base = {"allow_clients": [], "listen_addresses": [], "servers": {}} + base.update(kwargs) + return base + + def _want(self, **kwargs): + return self._have(**kwargs) + + def test_merged_adds_new_server(self): + want = self._want(servers={"new.server.com": []}) + have = self._have(servers={}) + cmds = build_commands(want, have, "merged") + self.assertIn(("set", ["service", "ntp", "server", "new.server.com"]), cmds) + + def test_merged_idempotent_existing_server(self): + want = self._want(servers={"time1.vyos.net": []}) + have = self._have(servers={"time1.vyos.net": []}) + cmds = build_commands(want, have, "merged") + self.assertEqual(cmds, []) + + def test_merged_adds_server_option(self): + want = self._want(servers={"time1.vyos.net": ["prefer"]}) + have = self._have(servers={"time1.vyos.net": []}) + cmds = build_commands(want, have, "merged") + self.assertIn(("set", ["service", "ntp", "server", "time1.vyos.net", "prefer"]), cmds) + + def test_replaced_removes_extra_server(self): + want = self._want(servers={"time1.vyos.net": []}) + have = self._have(servers={"time1.vyos.net": [], "time2.vyos.net": []}) + cmds = build_commands(want, have, "replaced") + self.assertIn(("delete", ["service", "ntp", "server", "time2.vyos.net"]), cmds) + + def test_replaced_removes_extra_allow_client(self): + want = self._want(allow_clients=["10.1.0.0/24"]) + have = self._have(allow_clients=["10.1.0.0/24", "10.2.0.0/24"]) + cmds = build_commands(want, have, "replaced") + self.assertIn( + ("delete", ["service", "ntp", "allow-client", "address", "10.2.0.0/24"]), + cmds, + ) + + def test_deleted_removes_all(self): + have = self._have( + servers={"time1.vyos.net": []}, + allow_clients=["10.0.0.0/24"], + listen_addresses=["192.168.1.1"], + ) + cmds = build_commands({}, have, "deleted") + self.assertEqual(len(cmds), 1) + self.assertEqual(cmds[0], ("delete", ["service", "ntp"])) + + def test_deleted_idempotent_when_empty(self): + have = self._have(servers={}, allow_clients=[], listen_addresses=[]) + cmds = build_commands({}, have, "deleted") + self.assertEqual(cmds, []) + + def test_overridden_deletes_then_merges(self): + want = self._want(servers={"new.server.com": []}) + have = self._have(servers={"old.server.com": []}) + cmds = build_commands(want, have, "overridden") + ops_paths = [(c[0], c[1]) for c in cmds] + self.assertIn(("delete", ["service", "ntp", "server", "old.server.com"]), ops_paths) + self.assertIn(("set", ["service", "ntp", "server", "new.server.com"]), ops_paths) + self.assertNotIn(("delete", ["service", "ntp", "server"]), ops_paths) + + def test_no_commands_when_already_correct(self): + state = {"allow_clients": ["10.0.0.0/24"], "listen_addresses": [], "servers": {}} + cmds = build_commands(state, state, "merged") + self.assertEqual(cmds, []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/modules/test_vyos_route_maps.py b/tests/unit/modules/test_vyos_route_maps.py new file mode 100644 index 0000000..97d814b --- /dev/null +++ b/tests/unit/modules/test_vyos_route_maps.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import json +import os +import unittest + +from unittest.mock import MagicMock + +from ansible_collections.vyos.rest.plugins.modules.vyos_route_maps import ( + _want_to_api_match, + _want_to_api_set, + build_commands, + get_running_config, +) + + +def load_fixture(filename): + fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures") + path = os.path.join(fixtures_dir, filename) + with open(path) as f: + return json.load(f) + + +class VyOSModuleTestCase(unittest.TestCase): + def setUp(self): + self.mock_vyos = MagicMock() + self.mock_vyos.get_config = MagicMock(return_value={}) + + def set_running_config(self, data): + self.mock_vyos.get_config.return_value = data + + +class TestVyOSRouteMapsGetRunning(VyOSModuleTestCase): + + def setUp(self): + super().setUp() + self.fixture = load_fixture("route_maps_running.json") + + def test_unwraps_route_map_nesting(self): + """API returns {"route-map": {"NAME": {...}}} — must unwrap.""" + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + names = [e["route_map"] for e in result] + self.assertIn("RM-TEST-EXPORT-POLICY", names) + self.assertIn("rm1", names) + # "route-map" itself must NOT appear as a route map name + self.assertNotIn("route-map", names) + + def test_parses_rule_action(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + rm = next(e for e in result if e["route_map"] == "RM-TEST-EXPORT-POLICY") + rule = rm["entries"][0] + self.assertEqual(rule["action"], "permit") + self.assertEqual(rule["sequence"], 10) + + def test_parses_match_peer(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + rm = next(e for e in result if e["route_map"] == "RM-TEST-EXPORT-POLICY") + rule = rm["entries"][0] + self.assertEqual(rule["match"]["peer"], "192.0.2.32") + + def test_parses_set_fields(self): + self.set_running_config(self.fixture) + result = get_running_config(self.mock_vyos) + rm = next(e for e in result if e["route_map"] == "RM-TEST-EXPORT-POLICY") + rule = rm["entries"][0] + self.assertEqual(rule["set"]["metric"], "5") + self.assertEqual(rule["set"]["aggregator"]["as"], "100") + self.assertEqual(rule["set"]["as-path"]["exclude"], "111") + + def test_empty_returns_empty_list(self): + self.set_running_config({}) + result = get_running_config(self.mock_vyos) + self.assertEqual(result, []) + + +class TestVyOSRouteMapsWantToApi(unittest.TestCase): + + def test_as_path_exclude_nested(self): + """as_path_exclude maps to nested as-path.exclude.""" + result = _want_to_api_set({"as_path_exclude": "111"}) + self.assertEqual(result["as-path"]["exclude"], "111") + + def test_metric_flat(self): + result = _want_to_api_set({"metric": "5"}) + self.assertEqual(result["metric"], "5") + + def test_aggregator_as(self): + result = _want_to_api_set({"aggregator": {"as": 100}}) + self.assertEqual(result["aggregator"]["as"], "100") + + def test_aggregator_as_underscore(self): + """aggregator.as_ is an alias for aggregator.as.""" + result = _want_to_api_set({"aggregator": {"as_": 100}}) + self.assertEqual(result["aggregator"]["as"], "100") + + def test_large_community_presence_node(self): + result = _want_to_api_set({"large_community": "none"}) + self.assertEqual(result["large-community"], {"none": {}}) + + def test_match_peer(self): + result = _want_to_api_match({"peer": "192.0.2.32"}) + self.assertEqual(result["peer"], "192.0.2.32") + + +class TestVyOSRouteMapsBuildCommands(unittest.TestCase): + + def _have_empty(self): + return [] + + def _have_with_rm(self): + return [ + { + "route_map": "RM1", + "entries": [ + { + "sequence": 10, + "action": "permit", + "match": {"peer": "192.0.2.32"}, + "set": {"metric": "5", "as-path": {"exclude": "111"}}, + }, + ], + }, + ] + + def test_merged_adds_new_rm(self): + config = [ + { + "route_map": "RM-NEW", + "entries": [{"sequence": 10, "action": "permit"}], + }, + ] + cmds = build_commands(config, self._have_empty(), "merged") + paths = [c[1] for c in cmds] + self.assertIn(["policy", "route-map", "RM-NEW", "rule", "10", "action", "permit"], paths) + + def test_merged_idempotent(self): + config = [ + { + "route_map": "RM1", + "entries": [ + { + "sequence": 10, + "action": "permit", + "match": {"peer": "192.0.2.32"}, + "set": {"metric": "5", "as_path_exclude": "111"}, + }, + ], + }, + ] + cmds = build_commands(config, self._have_with_rm(), "merged") + self.assertEqual(cmds, []) + + def test_deleted_no_config_deletes_all(self): + cmds = build_commands([], self._have_with_rm(), "deleted") + self.assertIn(("delete", ["policy", "route-map"]), cmds) + + def test_deleted_with_config_deletes_named(self): + config = [{"route_map": "RM1"}] + cmds = build_commands(config, self._have_with_rm(), "deleted") + self.assertIn(("delete", ["policy", "route-map", "RM1"]), cmds) + + def test_replaced_deletes_then_resets(self): + config = [ + { + "route_map": "RM1", + "entries": [{"sequence": 10, "action": "deny"}], + }, + ] + cmds = build_commands(config, self._have_with_rm(), "replaced") + ops = [c[0] for c in cmds] + # delete must come before set + self.assertIn("delete", ops) + self.assertIn("set", ops) + delete_idx = ops.index("delete") + set_idx = ops.index("set") + self.assertLess(delete_idx, set_idx) + + def test_overridden_removes_extra_rm(self): + config = [{"route_map": "RM-NEW", "entries": []}] + have = self._have_with_rm() # has RM1 + cmds = build_commands(config, have, "overridden") + self.assertIn(("delete", ["policy", "route-map", "RM1"]), cmds) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/test_vyos_rest_client.py b/tests/unit/test_vyos_rest_client.py index d476ea9..2bc2add 100644 --- a/tests/unit/test_vyos_rest_client.py +++ b/tests/unit/test_vyos_rest_client.py @@ -3,6 +3,7 @@ import json from unittest.mock import MagicMock, patch +from urllib.parse import parse_qs import pytest @@ -40,6 +41,14 @@ def _ok_response(data): return mock_resp +def _get_payload(mock_open): + """Extract and decode the JSON payload from a mocked open_url call.""" + call_args = mock_open.call_args + data_field = call_args[1]["data"] if "data" in call_args[1] else call_args[0][1] + parsed = parse_qs(data_field) + return json.loads(parsed["data"][0]) + + class TestVyOSRestClientInit: def test_base_url(self): client = _make_client() @@ -58,10 +67,10 @@ class TestConfigureSet: return_value=_ok_response(None), ) as mock_open: client.configure_set(["interfaces", "ethernet", "eth0"]) - call_args = mock_open.call_args - data_field = call_args[1]["data"] if "data" in call_args[1] else call_args[0][1] - assert '"op": "set"' in data_field - assert '"interfaces"' in data_field + payload = _get_payload(mock_open) + assert payload["op"] == "set" + assert payload["path"] == ["interfaces", "ethernet", "eth0"] + assert "value" not in payload def test_set_path_with_value(self): client = _make_client() @@ -70,9 +79,10 @@ class TestConfigureSet: return_value=_ok_response(None), ) as mock_open: client.configure_set(["system", "host-name"], "vyos") - call_args = mock_open.call_args - data_field = call_args[1]["data"] if "data" in call_args[1] else call_args[0][1] - assert '"value": "vyos"' in data_field + payload = _get_payload(mock_open) + assert payload["op"] == "set" + assert payload["path"] == ["system", "host-name"] + assert payload["value"] == "vyos" class TestConfigureDelete: @@ -83,9 +93,9 @@ class TestConfigureDelete: return_value=_ok_response(None), ) as mock_open: client.configure_delete(["protocols", "static", "route"]) - call_args = mock_open.call_args - data_field = call_args[1]["data"] if "data" in call_args[1] else call_args[0][1] - assert '"op": "delete"' in data_field + payload = _get_payload(mock_open) + assert payload["op"] == "delete" + assert payload["path"] == ["protocols", "static", "route"] class TestRetrieve: @@ -105,7 +115,7 @@ class TestRetrieve: "ansible_collections.vyos.rest.plugins.module_utils.vyos_rest.open_url", return_value=_ok_response(True), ): - assert client.retrieve_exists(["service", "ntp"]) is True + assert client.retrieve_exists(["service", "ssh"]) is True def test_exists_false(self): client = _make_client() |
