diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index ebe0477..6fc42e6 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6007,6 +6007,39 @@ def apic_vmm_inventory_sync_faults_check(**kwargs): recommended_action=recommended_action, doc_url=doc_url) +@check_wrapper(check_title='Rogue EP/COOP Exception MACs missing') +def rogue_ep_coop_exception_mac_check(cversion, tversion, **kwargs): + result = PASS + headers = ["Rogue Exception MACs Count", "presListener Count"] + data = [] + recommended_action = 'Remove the affected EP exception configurations and re-add them' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#rogue-epcoop-exception-macs-missing' + + # Target version check + if not tversion: + prints("Target version not provided, skipping check.") + return Result(result=MANUAL, msg=TVER_MISSING) + + # Check applicable only when upgrading from versions newer than 3.1(2v) to versions older than 6.1(3g) + if cversion.newer_than("3.1(2v)") and tversion.older_than("6.1(3g)"): + # endpoint to fetch the rogue exception MACs + exception_mac_api = 'fvRogueExceptionMac.json?query-target-filter=and(wcard(fvRogueExceptionMac.dn,"([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}"))' + + # endpoint to fetch the presListener entries + presListener_api = 'presListener.json?query-target-filter=and(wcard(presListener.dn,"exceptcont"))' + + exception_macs = icurl('class', exception_mac_api) + + if exception_macs: + prints("Found {} exception MACs, checking presListener entries...".format(len(exception_macs))) + presListener_response = icurl('class', presListener_api) + if len(presListener_response) >= 0 and len(presListener_response) < 32: + prints("Insufficient presListener entries ({} found) for {} exception MACs.".format(len(presListener_response), len(exception_macs))) + result = FAIL_O + data.append([len(exception_macs), len(presListener_response)]) + + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + # ---- Script Execution ---- @@ -6168,6 +6201,7 @@ class CheckManager: standby_sup_sync_check, isis_database_byte_check, configpush_shard_check, + rogue_ep_coop_exception_mac_check, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index fa1fc0e..605df7e 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -190,7 +190,8 @@ Items | Defect | This Script [Observer Database Size][d25] | CSCvw45531 | :white_check_mark: | :no_entry_sign: [Stale pconsRA Object][d26] | CSCwp22212 | :warning:{title="Deprecated"} | :no_entry_sign: [ISIS DTEPs Byte Size][d27] | CSCwp15375 | :white_check_mark: | :no_entry_sign: -[Policydist configpushShardCont Crash][d28] | CSCwp95515 | :white_check_mark: | +[Policydist configpushShardCont Crash][d28] | CSCwp95515 | :white_check_mark: | :no_entry_sign: +[Rogue EP/COOP Exception MACs missing][d29] | CSCwp64296 | :white_check_mark: | :no_entry_sign: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -220,6 +221,7 @@ Items | Defect | This Script [d26]: #stale-pconsra-object [d27]: #isis-dteps-byte-size [d28]: #policydist-configpushshardcont-crash +[d29]: #rogue-epcoop-exception-macs-missing ## General Check Details @@ -2614,6 +2616,15 @@ Due to [CSCwp95515][59], upgrading to an affected version while having any `conf If any instances of `configpushShardCont` are flagged by this script, Cisco TAC must be contacted to identify and resolve the underlying issue before performing the upgrade. +### Rogue EP/COOP Exception MACs missing + +Due to the defect [CSCwp64296][62], rogue endpoint (EP) and COOP exception MAC address configurations may be lost after a stateless reload of spine switches in an ACI fabric. The `presListener` MO, which holds the exception list configuration for the tenant shard, is missing or incomplete on the APIC side. This leads to spine switches not receiving the `rogueBDDef` configuration after reload. + +This script checks if the APIC version is in the affected range, whether rogue MACs are configured in the exception list, and if `presListener` MOs are missing. If all conditions are met, the check will flag the fabric as susceptible to CSCwp64296. + +As a workaround, remove the affected EP exception configurations and re-add them. To permanently resolve the issue, contact Cisco TAC to create the missing `presListener` MOs. + + [0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script [1]: https://www.cisco.com/c/dam/en/us/td/docs/Website/datacenter/apicmatrix/index.html [2]: https://www.cisco.com/c/en/us/support/switches/nexus-9000-series-switches/products-release-notes-list.html @@ -2676,3 +2687,4 @@ If any instances of `configpushShardCont` are flagged by this script, Cisco TAC [59]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp95515 [60]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#Inter [61]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#EnablePolicyCompression +[62]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp64296 \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/no_rogue_mac_response.json b/tests/checks/rogue_ep_coop_exception_mac_check/no_rogue_mac_response.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/no_rogue_mac_response.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont.json b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont.json new file mode 100644 index 0000000..bcaa988 --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont.json @@ -0,0 +1,386 @@ +[ + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-20/relnholder/rspresClass-[resregistry/resregistry-20/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.619-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-17/relnholder/rspresClass-[resregistry/resregistry-17/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.509-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-32/relnholder/rspresClass-[resregistry/resregistry-32/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.471-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-27/relnholder/rspresClass-[resregistry/resregistry-27/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.412-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-24/relnholder/rspresClass-[resregistry/resregistry-24/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.382-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-23/relnholder/rspresClass-[resregistry/resregistry-23/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.049-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-29/relnholder/rspresClass-[resregistry/resregistry-29/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.048-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-21/relnholder/rspresClass-[resregistry/resregistry-21/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.035-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-22/relnholder/rspresClass-[resregistry/resregistry-22/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.015-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-18/relnholder/rspresClass-[resregistry/resregistry-18/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.953-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-11/relnholder/rspresClass-[resregistry/resregistry-11/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.945-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-12/relnholder/rspresClass-[resregistry/resregistry-12/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.913-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-2/relnholder/rspresClass-[resregistry/resregistry-2/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.809-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-4/relnholder/rspresClass-[resregistry/resregistry-4/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.802-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-30/relnholder/rspresClass-[resregistry/resregistry-30/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.769-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-14/relnholder/rspresClass-[resregistry/resregistry-14/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.691-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-8/relnholder/rspresClass-[resregistry/resregistry-8/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.685-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-16/relnholder/rspresClass-[resregistry/resregistry-16/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.660-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-6/relnholder/rspresClass-[resregistry/resregistry-6/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.642-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-15/relnholder/rspresClass-[resregistry/resregistry-15/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.629-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-19/relnholder/rspresClass-[resregistry/resregistry-19/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.625-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-25/relnholder/rspresClass-[resregistry/resregistry-25/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.608-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-28/relnholder/rspresClass-[resregistry/resregistry-28/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.604-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-5/relnholder/rspresClass-[resregistry/resregistry-5/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.470-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-7/relnholder/rspresClass-[resregistry/resregistry-7/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.453-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-9/relnholder/rspresClass-[resregistry/resregistry-9/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.437-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-13/relnholder/rspresClass-[resregistry/resregistry-13/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.405-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-1/relnholder/rspresClass-[resregistry/resregistry-1/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.396-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-31/relnholder/rspresClass-[resregistry/resregistry-31/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.373-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-26/relnholder/rspresClass-[resregistry/resregistry-26/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.810-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-10/relnholder/rspresClass-[resregistry/resregistry-10/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.282-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-3/relnholder/rspresClass-[resregistry/resregistry-3/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.248-08:00", + "status": "" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_31_missing.json b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_31_missing.json new file mode 100644 index 0000000..09abfde --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_31_missing.json @@ -0,0 +1,14 @@ +[ + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-27/relnholder/rspresClass-[resregistry/resregistry-27/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.412-08:00", + "status": "" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_many_missing.json b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_many_missing.json new file mode 100644 index 0000000..7ecfd0f --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_many_missing.json @@ -0,0 +1,326 @@ +[ + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-20/relnholder/rspresClass-[resregistry/resregistry-20/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.619-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-17/relnholder/rspresClass-[resregistry/resregistry-17/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.509-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-32/relnholder/rspresClass-[resregistry/resregistry-32/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.471-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-27/relnholder/rspresClass-[resregistry/resregistry-27/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.412-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-24/relnholder/rspresClass-[resregistry/resregistry-24/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.382-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-23/relnholder/rspresClass-[resregistry/resregistry-23/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.049-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-29/relnholder/rspresClass-[resregistry/resregistry-29/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.048-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-21/relnholder/rspresClass-[resregistry/resregistry-21/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.035-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-22/relnholder/rspresClass-[resregistry/resregistry-22/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.015-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-18/relnholder/rspresClass-[resregistry/resregistry-18/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.953-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-14/relnholder/rspresClass-[resregistry/resregistry-14/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.691-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-8/relnholder/rspresClass-[resregistry/resregistry-8/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.685-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-16/relnholder/rspresClass-[resregistry/resregistry-16/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.660-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-6/relnholder/rspresClass-[resregistry/resregistry-6/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.642-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-15/relnholder/rspresClass-[resregistry/resregistry-15/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.629-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-19/relnholder/rspresClass-[resregistry/resregistry-19/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.625-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-25/relnholder/rspresClass-[resregistry/resregistry-25/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.608-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-28/relnholder/rspresClass-[resregistry/resregistry-28/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.604-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-5/relnholder/rspresClass-[resregistry/resregistry-5/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.470-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-7/relnholder/rspresClass-[resregistry/resregistry-7/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.453-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-9/relnholder/rspresClass-[resregistry/resregistry-9/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.437-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-13/relnholder/rspresClass-[resregistry/resregistry-13/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.405-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-1/relnholder/rspresClass-[resregistry/resregistry-1/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.396-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-31/relnholder/rspresClass-[resregistry/resregistry-31/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.373-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-26/relnholder/rspresClass-[resregistry/resregistry-26/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.810-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-10/relnholder/rspresClass-[resregistry/resregistry-10/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.282-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-3/relnholder/rspresClass-[resregistry/resregistry-3/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.248-08:00", + "status": "" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_one_missing.json b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_one_missing.json new file mode 100644 index 0000000..11ff0fd --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/presListener_exceptcont_one_missing.json @@ -0,0 +1,374 @@ +[ + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-20/relnholder/rspresClass-[resregistry/resregistry-20/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.619-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-17/relnholder/rspresClass-[resregistry/resregistry-17/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.509-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-32/relnholder/rspresClass-[resregistry/resregistry-32/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.471-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-27/relnholder/rspresClass-[resregistry/resregistry-27/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.412-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-24/relnholder/rspresClass-[resregistry/resregistry-24/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:56.382-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-23/relnholder/rspresClass-[resregistry/resregistry-23/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.049-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-29/relnholder/rspresClass-[resregistry/resregistry-29/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.048-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-21/relnholder/rspresClass-[resregistry/resregistry-21/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.035-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-22/relnholder/rspresClass-[resregistry/resregistry-22/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:55.015-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-18/relnholder/rspresClass-[resregistry/resregistry-18/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.953-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-11/relnholder/rspresClass-[resregistry/resregistry-11/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.945-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-12/relnholder/rspresClass-[resregistry/resregistry-12/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.913-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-2/relnholder/rspresClass-[resregistry/resregistry-2/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.809-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-4/relnholder/rspresClass-[resregistry/resregistry-4/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.802-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-30/relnholder/rspresClass-[resregistry/resregistry-30/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.769-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-14/relnholder/rspresClass-[resregistry/resregistry-14/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.691-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-8/relnholder/rspresClass-[resregistry/resregistry-8/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.685-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-16/relnholder/rspresClass-[resregistry/resregistry-16/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.660-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-6/relnholder/rspresClass-[resregistry/resregistry-6/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.642-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-15/relnholder/rspresClass-[resregistry/resregistry-15/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.629-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-19/relnholder/rspresClass-[resregistry/resregistry-19/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.625-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-25/relnholder/rspresClass-[resregistry/resregistry-25/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.608-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-28/relnholder/rspresClass-[resregistry/resregistry-28/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.604-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-5/relnholder/rspresClass-[resregistry/resregistry-5/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.470-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-7/relnholder/rspresClass-[resregistry/resregistry-7/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.453-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-9/relnholder/rspresClass-[resregistry/resregistry-9/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.437-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-13/relnholder/rspresClass-[resregistry/resregistry-13/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.405-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-1/relnholder/rspresClass-[resregistry/resregistry-1/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.396-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-31/relnholder/rspresClass-[resregistry/resregistry-31/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:54.373-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-26/relnholder/rspresClass-[resregistry/resregistry-26/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.810-08:00", + "status": "" + } + } + }, + { + "presListener": { + "attributes": { + "childAction": "", + "dn": "resregistry/resregistry-10/relnholder/rspresClass-[resregistry/resregistry-10/class-19076]/list-[exceptcont]", + "lcOwn": "local", + "lstDn": "exceptcont", + "modTs": "2025-09-22T00:05:53.282-08:00", + "status": "" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/rogue_mac_response.json b/tests/checks/rogue_ep_coop_exception_mac_check/rogue_mac_response.json new file mode 100644 index 0000000..b648d4d --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/rogue_mac_response.json @@ -0,0 +1,102 @@ +[ + { + "fvRogueExceptionMac": { + "attributes": { + "mac": "10:B3:D5:14:14:29", + "annotation": "", + "childAction": "", + "descr": "", + "dn": "uni/tn-Exception/BD-Exception_BD/rgexpmac-10:B3:D5:14:14:29", + "extMngdBy": "", + "lcOwn": "local", + "modTs": "2024-07-17T04:57:04.923+00:00", + "name": "", + "nameAlias": "", + "rn": "rgexpmac-10:B3:D5:14:14:29", + "status": "", + "uid": "16222", + "userdom": ":all:" + } + } + }, + { + "fvRogueExceptionMac": { + "attributes": { + "mac": "00:50:56:9A:1B:2C", + "annotation": "", + "childAction": "", + "descr": "", + "dn": "uni/tn-Production/BD-Prod_BD/rgexpmac-00:50:56:9A:1B:2C", + "extMngdBy": "", + "lcOwn": "local", + "modTs": "2024-07-18T10:22:15.456+00:00", + "name": "", + "nameAlias": "", + "rn": "rgexpmac-00:50:56:9A:1B:2C", + "status": "", + "uid": "16223", + "userdom": ":all:" + } + } + }, + { + "fvRogueExceptionMac": { + "attributes": { + "mac": "AA:BB:CC:DD:EE:FF", + "annotation": "", + "childAction": "", + "descr": "", + "dn": "uni/tn-Test/BD-Test_BD/rgexpmac-AA:BB:CC:DD:EE:FF", + "extMngdBy": "", + "lcOwn": "local", + "modTs": "2024-07-19T14:35:28.789+00:00", + "name": "", + "nameAlias": "", + "rn": "rgexpmac-AA:BB:CC:DD:EE:FF", + "status": "", + "uid": "16224", + "userdom": ":all:" + } + } + }, + { + "fvRogueExceptionMac": { + "attributes": { + "mac": "F0:1F:AF:2D:3E:4F", + "annotation": "", + "childAction": "", + "descr": "", + "dn": "uni/tn-Dev/BD-Dev_BD/rgexpmac-F0:1F:AF:2D:3E:4F", + "extMngdBy": "", + "lcOwn": "local", + "modTs": "2024-07-20T08:45:12.321+00:00", + "name": "", + "nameAlias": "", + "rn": "rgexpmac-F0:1F:AF:2D:3E:4F", + "status": "", + "uid": "16225", + "userdom": ":all:" + } + } + }, + { + "fvRogueExceptionMac": { + "attributes": { + "mac": "12:34:56:78:9A:BC", + "annotation": "", + "childAction": "", + "descr": "", + "dn": "uni/tn-Staging/BD-Staging_BD/rgexpmac-12:34:56:78:9A:BC", + "extMngdBy": "", + "lcOwn": "local", + "modTs": "2024-07-21T16:55:33.654+00:00", + "name": "", + "nameAlias": "", + "rn": "rgexpmac-12:34:56:78:9A:BC", + "status": "", + "uid": "16226", + "userdom": ":all:" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/rogue_ep_coop_exception_mac_check/test_rogue_ep_coop_exception_mac_check.py b/tests/checks/rogue_ep_coop_exception_mac_check/test_rogue_ep_coop_exception_mac_check.py new file mode 100644 index 0000000..2292a0f --- /dev/null +++ b/tests/checks/rogue_ep_coop_exception_mac_check/test_rogue_ep_coop_exception_mac_check.py @@ -0,0 +1,152 @@ +import os +import pytest +import logging +import importlib +from helpers.utils import read_data + +log = logging.getLogger(__name__) +dir = os.path.dirname(os.path.abspath(__file__)) + +script = importlib.import_module("aci-preupgrade-validation-script") + +test_function = "rogue_ep_coop_exception_mac_check" + +# icurl queries +exception_mac_api = 'fvRogueExceptionMac.json' +exception_mac_api += '?query-target-filter=and(wcard(fvRogueExceptionMac.dn,"([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}"))' + +presListener_api = 'presListener.json' +presListener_api += '?query-target-filter=and(wcard(presListener.dn,"exceptcont"))' + + +@pytest.mark.parametrize( + "icurl_outputs, tversion, cversion, expected_result", + [ + # PASS cases + # Non affected tversion, affected cversion, no exception MACs + ( + {exception_mac_api: read_data(dir, "no_rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(3g)", + "5.2(8e)", + script.PASS, + ), + # Non affected cversion, affected tversion, no exception MACs + ( + {exception_mac_api: read_data(dir, "no_rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.0(8h)", + "3.1(2v)", + script.PASS, + ), + # non affected cversion and tversion, no exception MACs + ( + {exception_mac_api: read_data(dir, "no_rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(4h)", + "3.1(2s)", + script.PASS, + ), + # non affected cversion and tversion, with exception MACs + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(4h)", + "3.1(2s)", + script.PASS, + ), + # affected edge cversion and tversion, no exception MACs + ( + {exception_mac_api: read_data(dir, "no_rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(3f)", + "5.2(7f)", + script.PASS, + ), + # affected cversion and tversion, no exception MACs + ( + {exception_mac_api: read_data(dir, "no_rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(2f)", + "5.2(8g)", + script.PASS, + ), + # affected version, exception MACs present but exceptcont listeners present + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.0(3e)", + "5.2(8g)E", + script.PASS, + ), + # affected edge version, exception MACs present but exceptcont listeners present + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "6.1(3f)", + "5.2(7f)", + script.PASS, + ), + # MANUAL cases + # tversion is not provided + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont.json")}, + "", + "5.2(8g)", + script.MANUAL, + ), + # FAIL cases + # affected edge version, exception MACs present, one missing exceptcont presListeners + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont_one_missing.json")}, + "6.1(3f)", + "5.2(7f)", + script.FAIL_O, + ), + # affected version, exception MACs present, 31 exceptcont presListeners missing + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont_31_missing.json")}, + "6.0(3e)", + "5.2(8g)E", + script.FAIL_O, + ), + # affected version, exception MACs present, many exceptcont presListeners missing + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: read_data(dir, "presListener_exceptcont_many_missing.json")}, + "6.1(2f)", + "5.2(8g)", + script.FAIL_O, + ), + # affected version, exception MACs present, no exceptcont presListeners missing + ( + {exception_mac_api: read_data(dir, "rogue_mac_response.json"), + presListener_api: []}, + "6.1(2f)", + "5.2(8g)", + script.FAIL_O, + ), + ], + ids=[ + "PASS_non_affected_tversion_affected_cversion_no_exception_MACs", + "PASS_non_affected_cversion_affected_tversion_no_exception_MACs", + "PASS_non_affected_cversion_tversion_no_exception_MACs", + "PASS_non_affected_cversion_tversion_with_exception_MACs", + "PASS_affected_edge_cversion_tversion_no_exception_MACs", + "PASS_affected_cversion_tversion_no_exception_MACs", + "PASS_affected_cversion_tversion_exception_MACs_with_exceptcont_listeners", + "PASS_affected_edge_cversion_tversion_exception_MACs_with_exceptcont_listeners", + "MANUAL_tversion_not_provided", + "FAIL_affected_edge_cversion_tversion_exception_MACs_one_missing_exceptcont_listener", + "FAIL_affected_cversion_tversion_exception_MACs_31_missing_exceptcont_listeners", + "FAIL_affected_cversion_tversion_exception_MACs_many_missing_exceptcont_listeners", + "FAIL_affected_cversion_tversion_exception_MACs_no_exceptcont_listeners", + ], +) +def test_rogue_ep_coop_exception_mac_check(run_check, mock_icurl, tversion, cversion, expected_result): + """Test rogue_ep_coop_exception_mac_check with various scenarios.""" + result = run_check(cversion=script.AciVersion(cversion), tversion=script.AciVersion(tversion) if tversion else None) + assert result.result == expected_result \ No newline at end of file