diff --git a/ntc_rosetta/parsers/openconfig/junos/__init__.py b/ntc_rosetta/parsers/openconfig/junos/__init__.py
index 69b01e7..85d6dee 100644
--- a/ntc_rosetta/parsers/openconfig/junos/__init__.py
+++ b/ntc_rosetta/parsers/openconfig/junos/__init__.py
@@ -1,3 +1,4 @@
+from copy import copy
from lxml import etree
from ntc_rosetta.parsers.openconfig.junos.openconfig_interfaces.interfaces import (
@@ -18,9 +19,17 @@ class JunosParser(parser.RootParser):
class Yangify(parser.ParserData):
def init(self) -> None:
- self.root_native["dev_conf"] = etree.fromstring(
- self.root_native["dev_conf"]
- )
+ parsed_xml = etree.fromstring(self.root_native["dev_conf"])
+ if parsed_xml.tag != "configuration":
+ parsed_xml = parsed_xml.find("configuration")
+ if parsed_xml is None:
+ raise AttributeError(
+ "Unable to locate 'configuration' tag in XML blob"
+ )
+ # We need to copy the XML element here, otherwise it will retain its parent
+ # references, meaning we can inadvertantly walk up the tree when we shouldn't.
+ parsed_xml = copy(parsed_xml)
+ self.root_native["dev_conf"] = parsed_xml
self.native["dev_conf"] = self.root_native["dev_conf"]
interfaces = Interfaces
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_fails_1 b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_fails_1
new file mode 100644
index 0000000..ed22ac8
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_fails_1
@@ -0,0 +1,33 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ 10
+ this is interface xe-0/0/1.10
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_passes_1
similarity index 100%
rename from tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf
rename to tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_passes_1
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_passes_2 b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_passes_2
new file mode 100644
index 0000000..ed22ac8
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_passes_2
@@ -0,0 +1,33 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ 10
+ this is interface xe-0/0/1.10
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_raises_AttributeError b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_raises_AttributeError
new file mode 100644
index 0000000..c073928
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/dev_conf_raises_AttributeError
@@ -0,0 +1,33 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ 10
+ this is interface xe-0/0/1.10
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_fails_1.json b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_fails_1.json
new file mode 100644
index 0000000..9a35d8f
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_fails_1.json
@@ -0,0 +1,61 @@
+{
+ "openconfig-interfaces:interfaces": {
+ "interface": [
+ {
+ "name": "xe-0/0/0",
+ "config": {
+ "name": "xe-0/0/0",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": false
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0,
+ "description": "this is interface xe-0/0/0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/1",
+ "config": {
+ "name": "xe-0/0/1",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/3",
+ "config": {
+ "name": "xe-0/0/3",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result.json b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_passes_1.json
similarity index 100%
rename from tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result.json
rename to tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_passes_1.json
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_passes_2.json b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_passes_2.json
new file mode 100644
index 0000000..fd9deb7
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_passes_2.json
@@ -0,0 +1,68 @@
+{
+ "openconfig-interfaces:interfaces": {
+ "interface": [
+ {
+ "name": "xe-0/0/0",
+ "config": {
+ "name": "xe-0/0/0",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": false
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0,
+ "description": "this is interface xe-0/0/0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/1",
+ "config": {
+ "name": "xe-0/0/1",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ },
+ {
+ "index": 10,
+ "config": {
+ "index": 10,
+ "description": "this is interface xe-0/0/1.10"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/3",
+ "config": {
+ "name": "xe-0/0/3",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_raises_AttributeError.json b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_raises_AttributeError.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-interfaces/parse/junos/config/result_raises_AttributeError.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf
deleted file mode 100644
index e9fc594..0000000
--- a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
- xe-0/0/0
-
- 0
- this is interface xe-0/0/0
-
-
-
- xe-0/0/1
-
- 0
-
-
- access
-
- 10
-
-
-
-
-
-
- xe-0/0/3
-
- 0
-
-
- trunk
-
- 10
- 20
-
-
-
-
-
-
-
-
- default
- 1
-
-
- prod
- 20
-
-
- 10
-
-
-
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_fails_1 b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_fails_1
new file mode 100644
index 0000000..9b28d45
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_fails_1
@@ -0,0 +1,58 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ access
+
+ 10
+
+
+
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+ trunk
+
+ 10
+ 20
+
+
+
+
+
+
+
+
+ default
+ 1
+
+
+ prod
+ 20
+
+
+ 10
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_1 b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_1
new file mode 100644
index 0000000..9b28d45
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_1
@@ -0,0 +1,58 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ access
+
+ 10
+
+
+
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+ trunk
+
+ 10
+ 20
+
+
+
+
+
+
+
+
+ default
+ 1
+
+
+ prod
+ 20
+
+
+ 10
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_2 b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_2
new file mode 100644
index 0000000..9b28d45
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_passes_2
@@ -0,0 +1,58 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ access
+
+ 10
+
+
+
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+ trunk
+
+ 10
+ 20
+
+
+
+
+
+
+
+
+ default
+ 1
+
+
+ prod
+ 20
+
+
+ 10
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_raises_AttributeError b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_raises_AttributeError
new file mode 100644
index 0000000..fd1dd4e
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/dev_conf_raises_AttributeError
@@ -0,0 +1,58 @@
+
+
+
+
+ xe-0/0/0
+
+ 0
+ this is interface xe-0/0/0
+
+
+
+ xe-0/0/1
+
+ 0
+
+
+ access
+
+ 10
+
+
+
+
+
+
+ xe-0/0/3
+
+ 0
+
+
+ trunk
+
+ 10
+ 20
+
+
+
+
+
+
+
+
+ default
+ 1
+
+
+ prod
+ 20
+
+
+ 10
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_fails_1.json b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_fails_1.json
new file mode 100644
index 0000000..93f35ab
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_fails_1.json
@@ -0,0 +1,102 @@
+{
+ "openconfig-interfaces:interfaces": {
+ "interface": [
+ {
+ "name": "xe-0/0/0",
+ "config": {
+ "name": "xe-0/0/0",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0,
+ "description": "this is interface xe-0/0/0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/1",
+ "config": {
+ "name": "xe-0/0/1",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ },
+ "openconfig-if-ethernet:ethernet": {
+ "openconfig-vlan:switched-vlan": {
+ "config": {
+ "interface-mode": "ACCESS",
+ "access-vlan": 10
+ }
+ }
+ }
+ },
+ {
+ "name": "xe-0/0/3",
+ "config": {
+ "name": "xe-0/0/3",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ },
+ "openconfig-if-ethernet:ethernet": {
+ "openconfig-vlan:switched-vlan": {
+ "config": {
+ "interface-mode": "TRUNK",
+ "trunk-vlans": [
+ 10,
+ 20
+ ]
+ }
+ }
+ }
+ }
+ ]
+ },
+ "openconfig-network-instance:network-instances": {
+ "network-instance": [
+ {
+ "name": "default",
+ "config": {
+ "name": "default"
+ },
+ "vlans": {
+ "vlan": [
+ {
+ "vlan-id": 1,
+ "config": {
+ "vlan-id": 1,
+ "name": "default",
+ "status": "ACTIVE"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result.json b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_passes_1.json
similarity index 100%
rename from tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result.json
rename to tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_passes_1.json
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_passes_2.json b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_passes_2.json
new file mode 100644
index 0000000..3b10139
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_passes_2.json
@@ -0,0 +1,117 @@
+{
+ "openconfig-interfaces:interfaces": {
+ "interface": [
+ {
+ "name": "xe-0/0/0",
+ "config": {
+ "name": "xe-0/0/0",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0,
+ "description": "this is interface xe-0/0/0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "xe-0/0/1",
+ "config": {
+ "name": "xe-0/0/1",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ },
+ "openconfig-if-ethernet:ethernet": {
+ "openconfig-vlan:switched-vlan": {
+ "config": {
+ "interface-mode": "ACCESS",
+ "access-vlan": 10
+ }
+ }
+ }
+ },
+ {
+ "name": "xe-0/0/3",
+ "config": {
+ "name": "xe-0/0/3",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true
+ },
+ "subinterfaces": {
+ "subinterface": [
+ {
+ "index": 0,
+ "config": {
+ "index": 0
+ }
+ }
+ ]
+ },
+ "openconfig-if-ethernet:ethernet": {
+ "openconfig-vlan:switched-vlan": {
+ "config": {
+ "interface-mode": "TRUNK",
+ "trunk-vlans": [
+ 10,
+ 20
+ ]
+ }
+ }
+ }
+ }
+ ]
+ },
+ "openconfig-network-instance:network-instances": {
+ "network-instance": [
+ {
+ "name": "default",
+ "config": {
+ "name": "default"
+ },
+ "vlans": {
+ "vlan": [
+ {
+ "vlan-id": 1,
+ "config": {
+ "vlan-id": 1,
+ "name": "default",
+ "status": "ACTIVE"
+ }
+ },
+ {
+ "vlan-id": 20,
+ "config": {
+ "vlan-id": 20,
+ "name": "prod",
+ "status": "ACTIVE"
+ }
+ },
+ {
+ "vlan-id": 10,
+ "config": {
+ "vlan-id": 10,
+ "status": "SUSPENDED"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_raises_AttributeError.json b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_raises_AttributeError.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/tests/models/openconfig/data/openconfig-vlan/parse/junos/config/result_raises_AttributeError.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/tests/models/openconfig/test_models.py b/tests/models/openconfig/test_models.py
index 384c1c9..aaa481d 100644
--- a/tests/models/openconfig/test_models.py
+++ b/tests/models/openconfig/test_models.py
@@ -57,9 +57,40 @@ class Test:
def test_parser(
self, model: str, driver: str, test_case_path: pathlib.Path
) -> None:
- with open(test_case_path.joinpath("dev_conf"), "r") as f:
+ device_config_files = []
+ result_files = []
+ for file_path in test_case_path.iterdir():
+ if file_path.is_file():
+ if file_path.name.startswith("dev_conf"):
+ device_config_files.append(file_path)
+ elif file_path.name.startswith("result"):
+ result_files.append(file_path)
+ # Assuming there is only a single testcase for this parser.
+ if len(device_config_files) == 1:
+ self._run_parser_test(
+ model, driver, device_config_files[0], result_files[0]
+ )
+ else:
+ for device_config, result in zip(
+ sorted(device_config_files), sorted(result_files)
+ ):
+ if "passes" in device_config.name:
+ self._run_parser_test(model, driver, device_config, result)
+ elif "fails" in device_config.name:
+ with pytest.raises(AssertionError):
+ self._run_parser_test(model, driver, device_config, result)
+ elif "_raises_" in device_config.name:
+ exception_name = device_config.name.split("_raises_")[-1]
+ with pytest.raises(eval(exception_name)):
+ self._run_parser_test(model, driver, device_config, result)
+
+ @staticmethod
+ def _run_parser_test(
+ model: str, driver: str, device_config: pathlib.Path, result: pathlib.Path
+ ) -> None:
+ with open(device_config, "r") as f:
dev_conf = f.read()
- with open(test_case_path.joinpath("result.json"), "r") as f:
+ with open(result, "r") as f:
structured = json.load(f)
driver_class = ntc_rosetta.get_driver(driver)
@@ -71,7 +102,7 @@ def test_parser(
include=filters[model]["include"],
exclude=filters[model]["exclude"],
)
- # print(json.dumps(parsed_obj.raw_value()))
+ # print(json.dumps(parsed_obj.raw_value()))
assert parsed_obj.raw_value() == structured, json.dumps(parsed_obj.raw_value())
def _test_translate(