From 4963f01f5d064602be8d194d10c4b83a088e8d97 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Fri, 25 Oct 2024 19:41:20 +0000 Subject: [PATCH 1/2] add more scenarios --- misc/discoverynode/testing/e2e/test_local | 2 +- misc/discoverynode/testing/e2e/test_local.py | 124 +++++++++++++++- misc/discoverynode/testing/e2e/unit_test.py | 141 +++++++++++++++++++ 3 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 misc/discoverynode/testing/e2e/unit_test.py diff --git a/misc/discoverynode/testing/e2e/test_local b/misc/discoverynode/testing/e2e/test_local index ab51a2c72..c95d35e59 100755 --- a/misc/discoverynode/testing/e2e/test_local +++ b/misc/discoverynode/testing/e2e/test_local @@ -10,7 +10,7 @@ if [[ -z $DN_SITE_PATH ]]; then exit 1 fi -if [[ $2 -ne "" ]]; then +if [[ $2 != "" ]]; then PYTEST_TARGET="-k $2" fi diff --git a/misc/discoverynode/testing/e2e/test_local.py b/misc/discoverynode/testing/e2e/test_local.py index 9d2808489..85c038996 100644 --- a/misc/discoverynode/testing/e2e/test_local.py +++ b/misc/discoverynode/testing/e2e/test_local.py @@ -21,12 +21,12 @@ import time import time from typing import Any -from typing import Any from typing import Iterator import re import pytest from typing import Final + ROOT_DIR = os.path.dirname(__file__) UDMI_DIR = str(Path(__file__).parents[4]) @@ -36,10 +36,10 @@ PROJECT_ID: Final = "localhost" # Some light hardcoding exists, so this is only guaranteed to work with localhost currently -assert os.environ["DN_TARGET"] == TARGET +#assert os.environ["DN_TARGET"] == TARGET # Assume the UDMI Directory is the UDMI directory and has not moved -assert UDMI_DIR.rsplit("/", 1)[1] == "udmi" +#assert UDMI_DIR.rsplit("/", 1)[1] == "udmi" def until_true(func: Callable, message: str, *, timeout = 0, interval = 0.1, **kwargs): @@ -78,6 +78,15 @@ def normalize_keys(target: dict[Any:Any], replacement, *args): normalize_keys(v, replacement, *args) return target +def deep_merge(dict1:dict[str:Any], dict2:dict[str:Any]) -> dict[str:Any]: + merged_dict = dict1 | dict2 + + for key in merged_dict: + if isinstance(merged_dict[key], dict) and key in dict1 and key in dict2: + merged_dict[key] = deep_merge(dict1[key], dict2[key]) + + return merged_dict + def localnet_block_from_id(id: int): """Generates localnet block f""" @@ -93,6 +102,33 @@ def localnet_block_from_id(id: int): } +def patch_metadata(patch:dict[str: Any], *, site_path: str, device_id:str) -> None: + """Patches the provided json_patch into the the devices metadata.json file. + + Args: + patch: Patch to apply. + device_id: Device ID. + site_path: Path to site model. + """ + metadata_path = os.path.join(site_path, "devices", device_id, "metadata.json") + + with open( + metadata_path, mode="r", encoding="utf-8" + ) as f: + existing_metadata = json.load(f) + + merged_metadata = deep_merge(existing_metadata, patch) + + with open( + os.path.join(metadata_path), mode="w", encoding="utf-8" + ) as f: + json.dump(merged_metadata, f, indent=2) + + +def extra_devices(site_path: str) -> [str]: + return list([x.stem for x in Path(site_path).glob("extras/*")]) + + def run(cmd: str) -> subprocess.CompletedProcess: """Runs the given command inside the UDMI directory and wait for it to complete""" # @@ -218,21 +254,21 @@ def _discovery_node( run("docker rm discoverynode-test-node") -def test_discovered_devices_are_created( +def test_new_discovered_devices_are_created( new_site_model, docker_devices, discovery_node ): new_site_model( site_path=SITE_PATH, delete=True, - devices=range(0), - devices_with_localnet_block=range(0), + devices=range(1,6), + devices_with_localnet_block=range(1,6), discovery_node_id="GAT-1", discovery_node_is_gateway=True, discovery_node_families=["bacnet"], ) - docker_devices(devices=range(1, 10)) + docker_devices(devices=range(1, 6)) info("deleting all devices") @@ -256,6 +292,80 @@ def test_discovered_devices_are_created( run(f"bin/registrar {SITE_PATH} {TARGET}") + assert len(extra_device(site_paths) == 0, "rediscovering a known device should not result in an extra device" + +def test_reconciling_an_extra_device( + new_site_model, docker_devices, discovery_node +): + + new_site_model( + site_path=SITE_PATH, + delete=True, + devices=range(1,2), + devices_with_localnet_block=range(0), + discovery_node_id="GAT-1", + discovery_node_is_gateway=True, + discovery_node_families=["bacnet"], + ) + + docker_devices(devices=range(1, 2)) + + run(f"bin/registrar {SITE_PATH} {TARGET} -d -x") + run(f"bin/registrar {SITE_PATH} {TARGET}") + + # Note: Start after running registrar preferably + discovery_node( + device_id="GAT-1", + site_path=SITE_PATH + ) + + run("bin/mapper GAT-1 provision") + run("bin/mapper GAT-1 discover") + time.sleep(30) + run(f"bin/registrar {SITE_PATH} {TARGET}") + + + assert len(extra_devices(SITE_PATH)) == 1, "extra device should be found" + + known_devices = list([x.stem for x in site_model.glob("devices/*")]) + for device in known_devices: + _,_, device_integer = device.partition("-") + + patch_metadata(localnet_block_from_id(int(device_integer)), site_path=SITE_PATH, device_id=device) + + run(f"bin/registrar {SITE_PATH} {TARGET}") + + assert len(extra_devices) == 0, "reconciled device should be deleted as an extra device" + +def test_discovering_new_devices( + new_site_model, docker_devices, discovery_node +): + + new_site_model( + site_path=SITE_PATH, + delete=True, + devices=range(0), + devices_with_localnet_block=range(0), + discovery_node_id="GAT-1", + discovery_node_is_gateway=True, + discovery_node_families=["bacnet"], + ) + docker_devices(devices=range(1, 10)) + + run(f"bin/registrar {SITE_PATH} {TARGET} -d -x") + run(f"bin/registrar {SITE_PATH} {TARGET}") + + # Note: Start after running registrar preferably + discovery_node( + device_id="GAT-1", + site_path=SITE_PATH + ) + + run("bin/mapper GAT-1 provision") + run("bin/mapper GAT-1 discover") + time.sleep(30) + run(f"bin/registrar {SITE_PATH} {TARGET}") + site_model = Path(SITE_PATH) extra_devices = list([x.stem for x in site_model.glob("extras/*")]) assert len(extra_devices) == 9, "found exactly 9 devices" diff --git a/misc/discoverynode/testing/e2e/unit_test.py b/misc/discoverynode/testing/e2e/unit_test.py new file mode 100644 index 000000000..9d85b4c82 --- /dev/null +++ b/misc/discoverynode/testing/e2e/unit_test.py @@ -0,0 +1,141 @@ +import test_local + + +def test_deep_merge(): + dict1 = {"a": {"b": 1, "c": {"d": 2}}} + dict2 = {"a": {"c": 3, "c": {"d": 3}}} + result = {"a": {"b": 1, "c": 3, "c": {"d": 3}}} + assert test_local.deep_merge(dict1, dict2) == result + + metadata = { + "pointset": { + "points": { + "filter_alarm_pressure_status": { + "units": "No-units", + "ref": "BV11.present_value", + }, + "filter_differential_pressure_sensor": { + "units": "Degrees-Celsius", + "ref": "AV12.present_value", + "baseline_value": 10, + "baseline_tolerance": 2, + }, + "filter_differential_pressure_setpoint": { + "units": "Bars", + "writable": True, + "baseline_value": 98, + }, + } + }, + "system": { + "hardware": {"make": "BOS", "model": "pubber"}, + "software": {"firmware": "v1"}, + "location": { + "site": "ZZ-TRI-FECTA-AHU", + "section": "2-3N8C", + "position": {"x": 111.0, "y": 102.3}, + }, + "physical_tag": { + "asset": {"guid": "drw://TBC", "site": "ZZ-TRI-FECTA", "name": "AHU-1"} + }, + }, + "cloud": {"auth_type": "RS256"}, + "discovery": {"families": {"vendor": {}}}, + "localnet": { + "families": { + "ipv4": {"addr": "192.168.2.1"}, + "ether": {"addr": "00:50:b6:ed:5f:77"}, + "vendor": {"addr": "28179023"}, + } + }, + "testing": { + "targets": { + "applied": { + "target_point": "filter_differential_pressure_setpoint", + "target_value": 60, + }, + "failure": { + "target_point": "filter_alarm_pressure_status", + "target_value": False, + }, + "invalid": { + "target_point": "filter_differential_pressure_sensor", + "target_value": 15, + }, + } + }, + "version": "1.4.1", + "timestamp": "2020-05-01T13:39:07Z", + } + + expected_metadata = { + "pointset": { + "points": { + "filter_alarm_pressure_status": { + "units": "No-units", + "ref": "BV11.present_value", + }, + "filter_differential_pressure_sensor": { + "units": "Degrees-Celsius", + "ref": "AV12.present_value", + "baseline_value": 10, + "baseline_tolerance": 2, + }, + "filter_differential_pressure_setpoint": { + "units": "Bars", + "writable": True, + "baseline_value": 98, + }, + } + }, + "system": { + "hardware": {"make": "BOS", "model": "pubber"}, + "software": {"firmware": "v1"}, + "location": { + "site": "ZZ-TRI-FECTA-AHU", + "section": "2-3N8C", + "position": {"x": 111.0, "y": 102.3}, + }, + "physical_tag": { + "asset": {"guid": "drw://TBC", "site": "ZZ-TRI-FECTA", "name": "AHU-1"} + }, + }, + "cloud": {"auth_type": "RS256"}, + "discovery": {"families": {"vendor": {}}}, + "localnet": { + "families": { + "ipv4": {"addr": "192.168.2.2"}, + "ether": {"addr": "00:50:b6:ed:5f:77"}, + "vendor": {"addr": "28179023"}, + "modbus": {"addr": "123"}, + } + }, + "testing": { + "targets": { + "applied": { + "target_point": "filter_differential_pressure_setpoint", + "target_value": 60, + }, + "failure": { + "target_point": "filter_alarm_pressure_status", + "target_value": False, + }, + "invalid": { + "target_point": "filter_differential_pressure_sensor", + "target_value": 15, + }, + } + }, + "version": "1.4.1", + "timestamp": "2020-05-01T13:39:07Z", + } + + merged_metadata = test_local.deep_merge( + metadata, + { + "localnet": { + "families": {"ipv4": {"addr": "192.168.2.2"}, "modbus": {"addr": "123"}} + } + }, + ) + assert merged_metadata == expected_metadata From b605a90047711fd45d6005cebe304a4364954e6a Mon Sep 17 00:00:00 2001 From: Noureddine Date: Fri, 25 Oct 2024 19:43:35 +0000 Subject: [PATCH 2/2] syntax --- misc/discoverynode/testing/e2e/test_local.py | 3 +- misc/discoverynode/testing/e2e/unit_test.py | 133 ------------------- 2 files changed, 1 insertion(+), 135 deletions(-) diff --git a/misc/discoverynode/testing/e2e/test_local.py b/misc/discoverynode/testing/e2e/test_local.py index 85c038996..55577a175 100644 --- a/misc/discoverynode/testing/e2e/test_local.py +++ b/misc/discoverynode/testing/e2e/test_local.py @@ -292,7 +292,7 @@ def test_new_discovered_devices_are_created( run(f"bin/registrar {SITE_PATH} {TARGET}") - assert len(extra_device(site_paths) == 0, "rediscovering a known device should not result in an extra device" + assert len(extra_device(site_paths)) == 0, "rediscovering a known device should not result in an extra device" def test_reconciling_an_extra_device( new_site_model, docker_devices, discovery_node @@ -324,7 +324,6 @@ def test_reconciling_an_extra_device( time.sleep(30) run(f"bin/registrar {SITE_PATH} {TARGET}") - assert len(extra_devices(SITE_PATH)) == 1, "extra device should be found" known_devices = list([x.stem for x in site_model.glob("devices/*")]) diff --git a/misc/discoverynode/testing/e2e/unit_test.py b/misc/discoverynode/testing/e2e/unit_test.py index 9d85b4c82..9986f6c43 100644 --- a/misc/discoverynode/testing/e2e/unit_test.py +++ b/misc/discoverynode/testing/e2e/unit_test.py @@ -6,136 +6,3 @@ def test_deep_merge(): dict2 = {"a": {"c": 3, "c": {"d": 3}}} result = {"a": {"b": 1, "c": 3, "c": {"d": 3}}} assert test_local.deep_merge(dict1, dict2) == result - - metadata = { - "pointset": { - "points": { - "filter_alarm_pressure_status": { - "units": "No-units", - "ref": "BV11.present_value", - }, - "filter_differential_pressure_sensor": { - "units": "Degrees-Celsius", - "ref": "AV12.present_value", - "baseline_value": 10, - "baseline_tolerance": 2, - }, - "filter_differential_pressure_setpoint": { - "units": "Bars", - "writable": True, - "baseline_value": 98, - }, - } - }, - "system": { - "hardware": {"make": "BOS", "model": "pubber"}, - "software": {"firmware": "v1"}, - "location": { - "site": "ZZ-TRI-FECTA-AHU", - "section": "2-3N8C", - "position": {"x": 111.0, "y": 102.3}, - }, - "physical_tag": { - "asset": {"guid": "drw://TBC", "site": "ZZ-TRI-FECTA", "name": "AHU-1"} - }, - }, - "cloud": {"auth_type": "RS256"}, - "discovery": {"families": {"vendor": {}}}, - "localnet": { - "families": { - "ipv4": {"addr": "192.168.2.1"}, - "ether": {"addr": "00:50:b6:ed:5f:77"}, - "vendor": {"addr": "28179023"}, - } - }, - "testing": { - "targets": { - "applied": { - "target_point": "filter_differential_pressure_setpoint", - "target_value": 60, - }, - "failure": { - "target_point": "filter_alarm_pressure_status", - "target_value": False, - }, - "invalid": { - "target_point": "filter_differential_pressure_sensor", - "target_value": 15, - }, - } - }, - "version": "1.4.1", - "timestamp": "2020-05-01T13:39:07Z", - } - - expected_metadata = { - "pointset": { - "points": { - "filter_alarm_pressure_status": { - "units": "No-units", - "ref": "BV11.present_value", - }, - "filter_differential_pressure_sensor": { - "units": "Degrees-Celsius", - "ref": "AV12.present_value", - "baseline_value": 10, - "baseline_tolerance": 2, - }, - "filter_differential_pressure_setpoint": { - "units": "Bars", - "writable": True, - "baseline_value": 98, - }, - } - }, - "system": { - "hardware": {"make": "BOS", "model": "pubber"}, - "software": {"firmware": "v1"}, - "location": { - "site": "ZZ-TRI-FECTA-AHU", - "section": "2-3N8C", - "position": {"x": 111.0, "y": 102.3}, - }, - "physical_tag": { - "asset": {"guid": "drw://TBC", "site": "ZZ-TRI-FECTA", "name": "AHU-1"} - }, - }, - "cloud": {"auth_type": "RS256"}, - "discovery": {"families": {"vendor": {}}}, - "localnet": { - "families": { - "ipv4": {"addr": "192.168.2.2"}, - "ether": {"addr": "00:50:b6:ed:5f:77"}, - "vendor": {"addr": "28179023"}, - "modbus": {"addr": "123"}, - } - }, - "testing": { - "targets": { - "applied": { - "target_point": "filter_differential_pressure_setpoint", - "target_value": 60, - }, - "failure": { - "target_point": "filter_alarm_pressure_status", - "target_value": False, - }, - "invalid": { - "target_point": "filter_differential_pressure_sensor", - "target_value": 15, - }, - } - }, - "version": "1.4.1", - "timestamp": "2020-05-01T13:39:07Z", - } - - merged_metadata = test_local.deep_merge( - metadata, - { - "localnet": { - "families": {"ipv4": {"addr": "192.168.2.2"}, "modbus": {"addr": "123"}} - } - }, - ) - assert merged_metadata == expected_metadata