Loading .gitlab-ci.yml +24 −24 Original line number Diff line number Diff line Loading @@ -23,38 +23,38 @@ stages: # include the individual .gitlab-ci.yml of each micro-service and tests include: #- local: '/manifests/.gitlab-ci.yml' - local: '/src/monitoring/.gitlab-ci.yml' - local: '/src/nbi/.gitlab-ci.yml' - local: '/src/context/.gitlab-ci.yml' #- local: '/src/monitoring/.gitlab-ci.yml' #- local: '/src/nbi/.gitlab-ci.yml' #- local: '/src/context/.gitlab-ci.yml' - local: '/src/device/.gitlab-ci.yml' - local: '/src/service/.gitlab-ci.yml' - local: '/src/dbscanserving/.gitlab-ci.yml' - local: '/src/opticalattackmitigator/.gitlab-ci.yml' - local: '/src/opticalattackdetector/.gitlab-ci.yml' - local: '/src/opticalattackmanager/.gitlab-ci.yml' - local: '/src/opticalcontroller/.gitlab-ci.yml' - local: '/src/ztp/.gitlab-ci.yml' - local: '/src/policy/.gitlab-ci.yml' - local: '/src/automation/.gitlab-ci.yml' - local: '/src/forecaster/.gitlab-ci.yml' #- local: '/src/dbscanserving/.gitlab-ci.yml' #- local: '/src/opticalattackmitigator/.gitlab-ci.yml' #- local: '/src/opticalattackdetector/.gitlab-ci.yml' #- local: '/src/opticalattackmanager/.gitlab-ci.yml' #- local: '/src/opticalcontroller/.gitlab-ci.yml' #- local: '/src/ztp/.gitlab-ci.yml' #- local: '/src/policy/.gitlab-ci.yml' #- local: '/src/automation/.gitlab-ci.yml' #- local: '/src/forecaster/.gitlab-ci.yml' #- local: '/src/webui/.gitlab-ci.yml' #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' - local: '/src/slice/.gitlab-ci.yml' #- local: '/src/slice/.gitlab-ci.yml' #- local: '/src/interdomain/.gitlab-ci.yml' - local: '/src/pathcomp/.gitlab-ci.yml' #- local: '/src/pathcomp/.gitlab-ci.yml' #- local: '/src/dlt/.gitlab-ci.yml' - local: '/src/load_generator/.gitlab-ci.yml' - local: '/src/bgpls_speaker/.gitlab-ci.yml' - local: '/src/kpi_manager/.gitlab-ci.yml' - local: '/src/kpi_value_api/.gitlab-ci.yml' - local: '/src/kpi_value_writer/.gitlab-ci.yml' - local: '/src/telemetry/.gitlab-ci.yml' - local: '/src/analytics/.gitlab-ci.yml' - local: '/src/qos_profile/.gitlab-ci.yml' - local: '/src/vnt_manager/.gitlab-ci.yml' - local: '/src/e2e_orchestrator/.gitlab-ci.yml' #- local: '/src/load_generator/.gitlab-ci.yml' #- local: '/src/bgpls_speaker/.gitlab-ci.yml' #- local: '/src/kpi_manager/.gitlab-ci.yml' #- local: '/src/kpi_value_api/.gitlab-ci.yml' #- local: '/src/kpi_value_writer/.gitlab-ci.yml' #- local: '/src/telemetry/.gitlab-ci.yml' #- local: '/src/analytics/.gitlab-ci.yml' #- local: '/src/qos_profile/.gitlab-ci.yml' #- local: '/src/vnt_manager/.gitlab-ci.yml' #- local: '/src/e2e_orchestrator/.gitlab-ci.yml' # This should be last one: end-to-end integration tests - local: '/src/tests/.gitlab-ci.yml' src/device/.gitlab-ci.yml +2 −2 Original line number Diff line number Diff line Loading @@ -97,8 +97,8 @@ unit_test_device: - sleep 5 - docker ps -a - docker logs $IMAGE_NAME - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report_emulated.xml" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_ietf_actn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_actn.xml" #- docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report_emulated.xml" #- docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_ietf_actn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_actn.xml" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_qkd_mock_connectivity.py" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_qkd_compliance.py" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_mock_qkd_node.py" Loading src/service/.gitlab-ci.yml +41 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ unit_test service: docker run --name nats -d --network=teraflowbridge -p 4222:4222 -p 8222:8222 nats:2.9 --http_port 8222 --user tfs --pass tfs123 - echo "Waiting for initialization..." - while ! docker logs crdb 2>&1 | grep -q 'finished creating default user \"tfs\"'; do sleep 1; done - while ! docker logs crdb 2>&1 | grep -q 'finished creating default user "tfs"'; do sleep 1; done - docker logs crdb - while ! docker logs nats 2>&1 | grep -q 'Server is ready'; do sleep 1; done - docker logs nats Loading Loading @@ -158,6 +158,46 @@ unit_test service: "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" # QKD Mock Nodes Deployment - echo "Starting stage: deploy_mock_nodes" - for port in 11111 22222 33333; do if lsof -i:$port >/dev/null 2>&1; then echo "Freeing up port $port..." fuser -k $port/tcp fi done - MOCK_NODES_DIR="$PWD/src/tests/tools/mock_qkd_nodes" - if [ -d "$MOCK_NODES_DIR" ]; then cd "$MOCK_NODES_DIR" || exit ./start.sh & MOCK_NODES_PID=$! else echo "Error: Mock QKD nodes directory '$MOCK_NODES_DIR' not found." exit 1 fi - echo "Waiting for mock nodes to be up..." - RETRY_COUNT=0 - MAX_RETRIES=15 - while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do if curl -s http://127.0.0.1:11111 > /dev/null && \ curl -s http://127.0.0.1:22222 > /dev/null && \ curl -s http://127.0.0.1:33333 > /dev/null; then echo "Mock nodes are up!" break else echo "Mock nodes not ready, retrying in 5 seconds..." RETRY_COUNT=$((RETRY_COUNT + 1)) sleep 5 fi done - if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then echo "Error: Mock nodes failed to start after multiple attempts." exit 1 fi # Run QKD Bootstrap Test - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose service/tests/qkd/test_functional_bootstrap.py" coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' after_script: # Check status after the tests Loading src/device/tests/qkd/unit/descriptorQKD_links.json→src/service/tests/qkd/descriptorQKD_links.json +20 −24 Original line number Diff line number Diff line Loading @@ -10,68 +10,64 @@ "device_id": {"device_uuid": {"uuid": "QKD1"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "11111"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} }, { "device_id": {"device_uuid": {"uuid": "QKD2"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "22222"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} }, { "device_id": {"device_uuid": {"uuid": "QKD3"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "33333"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} } ], "links": [ { "link_id": {"link_uuid": {"uuid": "QKD1/10.0.2.10:1001==QKD2/10.0.2.10:2001"}}, "link_id": {"link_uuid": {"uuid": "QKD1/<YOUR_MACHINE_IP>:1001==QKD2/<YOUR_MACHINE_IP>:2001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "10.0.2.10:1001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2001"}} {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:1001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD2/10.0.2.10:2001==QKD1/10.0.2.10:1001"}}, "link_id": {"link_uuid": {"uuid": "QKD2/<YOUR_MACHINE_IP>:2001==QKD1/<YOUR_MACHINE_IP>:1001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2001"}}, {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "10.0.2.10:1001"}} {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2001"}}, {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:1001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD2/10.0.2.10:2002==QKD3/10.0.2.10:3001"}}, "link_id": {"link_uuid": {"uuid": "QKD2/<YOUR_MACHINE_IP>:2002==QKD3/<YOUR_MACHINE_IP>:3001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2002"}}, {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "10.0.2.10:3001"}} {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2002"}}, {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:3001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD3/10.0.2.10:3001==QKD2/10.0.2.10:2002"}}, "link_id": {"link_uuid": {"uuid": "QKD3/<YOUR_MACHINE_IP>:3001==QKD2/<YOUR_MACHINE_IP>:2002"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "10.0.2.10:3001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2002"}} {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:3001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2002"}} ] } ] } No newline at end of file src/service/tests/qkd/test_functional_bootstrap.py 0 → 100644 +152 −0 Original line number Diff line number Diff line # Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging, os, time, json, socket, re from common.Constants import DEFAULT_CONTEXT_NAME from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum, Empty from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient from tests.Fixtures import context_client, device_client # pylint: disable=unused-import LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) # Update the path to your QKD descriptor file DESCRIPTOR_FILE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'descriptorQKD_links.json') ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) def load_descriptor_with_runtime_ip(descriptor_file_path): """ Load the descriptor file and replace placeholder IP with the machine's IP address. """ with open(descriptor_file_path, 'r') as descriptor_file: descriptor = descriptor_file.read() # Get the current machine's IP address try: # Use socket to get the local IP address directly from the network interface s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) current_ip = s.getsockname()[0] s.close() except Exception as e: raise Exception(f"Unable to get the IP address: {str(e)}") # Replace all occurrences of <YOUR_MACHINE_IP> with the current IP updated_descriptor = re.sub(r"<YOUR_MACHINE_IP>", current_ip, descriptor) # Write updated descriptor back with open(descriptor_file_path, 'w') as descriptor_file: descriptor_file.write(updated_descriptor) return json.loads(updated_descriptor) def load_and_process_descriptor(context_client, device_client, descriptor_file_path): """ Function to load and process descriptor programmatically, similar to what WebUI does. """ print(f"Loading descriptor from file: {descriptor_file_path}") try: # Update the descriptor with the runtime IP address descriptor = load_descriptor_with_runtime_ip(descriptor_file_path) # Initialize DescriptorLoader with the updated descriptor file descriptor_loader = DescriptorLoader( descriptors_file=descriptor_file_path, context_client=context_client, device_client=device_client ) # Process and validate the descriptor print("Processing the descriptor...") results = descriptor_loader.process() print(f"Descriptor processing results: {results}") print("Checking descriptor load results...") check_descriptor_load_results(results, descriptor_loader) print("Validating descriptor...") descriptor_loader.validate() print("Descriptor validated successfully.") except Exception as e: LOGGER.error(f"Failed to load and process descriptor: {e}") raise e def test_qkd_scenario_bootstrap( context_client: ContextClient, # pylint: disable=redefined-outer-name device_client: DeviceClient, # pylint: disable=redefined-outer-name ) -> None: """ This test validates that the QKD scenario is correctly bootstrapped. """ print("Starting QKD scenario bootstrap test...") # Check if context_client and device_client are instantiated if context_client is None: print("Error: context_client is not instantiated!") else: print(f"context_client is instantiated: {context_client}") if device_client is None: print("Error: device_client is not instantiated!") else: print(f"device_client is instantiated: {device_client}") # Validate empty scenario print("Validating empty scenario...") validate_empty_scenario(context_client) # Load the descriptor load_and_process_descriptor(context_client, device_client, DESCRIPTOR_FILE_PATH) def test_qkd_devices_enabled( context_client: ContextClient, # pylint: disable=redefined-outer-name ) -> None: """ This test validates that the QKD devices are enabled. """ print("Starting QKD devices enabled test...") # Check if context_client is instantiated if context_client is None: print("Error: context_client is not instantiated!") else: print(f"context_client is instantiated: {context_client}") DEVICE_OP_STATUS_ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED num_devices = -1 num_devices_enabled, num_retry = 0, 0 while (num_devices != num_devices_enabled) and (num_retry < 10): print(f"Attempt {num_retry + 1}: Checking device status...") time.sleep(1.0) # Add a delay to allow for device enablement response = context_client.ListDevices(Empty()) num_devices = len(response.devices) print(f"Total devices found: {num_devices}") num_devices_enabled = 0 for device in response.devices: if device.device_operational_status == DEVICE_OP_STATUS_ENABLED: num_devices_enabled += 1 print(f"Devices enabled: {num_devices_enabled}/{num_devices}") num_retry += 1 # Final check to ensure all devices are enabled print(f"Final device status: {num_devices_enabled}/{num_devices} devices enabled.") assert num_devices_enabled == num_devices print("QKD devices enabled test completed.") No newline at end of file Loading
.gitlab-ci.yml +24 −24 Original line number Diff line number Diff line Loading @@ -23,38 +23,38 @@ stages: # include the individual .gitlab-ci.yml of each micro-service and tests include: #- local: '/manifests/.gitlab-ci.yml' - local: '/src/monitoring/.gitlab-ci.yml' - local: '/src/nbi/.gitlab-ci.yml' - local: '/src/context/.gitlab-ci.yml' #- local: '/src/monitoring/.gitlab-ci.yml' #- local: '/src/nbi/.gitlab-ci.yml' #- local: '/src/context/.gitlab-ci.yml' - local: '/src/device/.gitlab-ci.yml' - local: '/src/service/.gitlab-ci.yml' - local: '/src/dbscanserving/.gitlab-ci.yml' - local: '/src/opticalattackmitigator/.gitlab-ci.yml' - local: '/src/opticalattackdetector/.gitlab-ci.yml' - local: '/src/opticalattackmanager/.gitlab-ci.yml' - local: '/src/opticalcontroller/.gitlab-ci.yml' - local: '/src/ztp/.gitlab-ci.yml' - local: '/src/policy/.gitlab-ci.yml' - local: '/src/automation/.gitlab-ci.yml' - local: '/src/forecaster/.gitlab-ci.yml' #- local: '/src/dbscanserving/.gitlab-ci.yml' #- local: '/src/opticalattackmitigator/.gitlab-ci.yml' #- local: '/src/opticalattackdetector/.gitlab-ci.yml' #- local: '/src/opticalattackmanager/.gitlab-ci.yml' #- local: '/src/opticalcontroller/.gitlab-ci.yml' #- local: '/src/ztp/.gitlab-ci.yml' #- local: '/src/policy/.gitlab-ci.yml' #- local: '/src/automation/.gitlab-ci.yml' #- local: '/src/forecaster/.gitlab-ci.yml' #- local: '/src/webui/.gitlab-ci.yml' #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' - local: '/src/slice/.gitlab-ci.yml' #- local: '/src/slice/.gitlab-ci.yml' #- local: '/src/interdomain/.gitlab-ci.yml' - local: '/src/pathcomp/.gitlab-ci.yml' #- local: '/src/pathcomp/.gitlab-ci.yml' #- local: '/src/dlt/.gitlab-ci.yml' - local: '/src/load_generator/.gitlab-ci.yml' - local: '/src/bgpls_speaker/.gitlab-ci.yml' - local: '/src/kpi_manager/.gitlab-ci.yml' - local: '/src/kpi_value_api/.gitlab-ci.yml' - local: '/src/kpi_value_writer/.gitlab-ci.yml' - local: '/src/telemetry/.gitlab-ci.yml' - local: '/src/analytics/.gitlab-ci.yml' - local: '/src/qos_profile/.gitlab-ci.yml' - local: '/src/vnt_manager/.gitlab-ci.yml' - local: '/src/e2e_orchestrator/.gitlab-ci.yml' #- local: '/src/load_generator/.gitlab-ci.yml' #- local: '/src/bgpls_speaker/.gitlab-ci.yml' #- local: '/src/kpi_manager/.gitlab-ci.yml' #- local: '/src/kpi_value_api/.gitlab-ci.yml' #- local: '/src/kpi_value_writer/.gitlab-ci.yml' #- local: '/src/telemetry/.gitlab-ci.yml' #- local: '/src/analytics/.gitlab-ci.yml' #- local: '/src/qos_profile/.gitlab-ci.yml' #- local: '/src/vnt_manager/.gitlab-ci.yml' #- local: '/src/e2e_orchestrator/.gitlab-ci.yml' # This should be last one: end-to-end integration tests - local: '/src/tests/.gitlab-ci.yml'
src/device/.gitlab-ci.yml +2 −2 Original line number Diff line number Diff line Loading @@ -97,8 +97,8 @@ unit_test_device: - sleep 5 - docker ps -a - docker logs $IMAGE_NAME - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report_emulated.xml" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_ietf_actn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_actn.xml" #- docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report_emulated.xml" #- docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_ietf_actn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_actn.xml" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_qkd_mock_connectivity.py" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_qkd_compliance.py" - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose device/tests/qkd/unit/test_mock_qkd_node.py" Loading
src/service/.gitlab-ci.yml +41 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ unit_test service: docker run --name nats -d --network=teraflowbridge -p 4222:4222 -p 8222:8222 nats:2.9 --http_port 8222 --user tfs --pass tfs123 - echo "Waiting for initialization..." - while ! docker logs crdb 2>&1 | grep -q 'finished creating default user \"tfs\"'; do sleep 1; done - while ! docker logs crdb 2>&1 | grep -q 'finished creating default user "tfs"'; do sleep 1; done - docker logs crdb - while ! docker logs nats 2>&1 | grep -q 'Server is ready'; do sleep 1; done - docker logs nats Loading Loading @@ -158,6 +158,46 @@ unit_test service: "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" # QKD Mock Nodes Deployment - echo "Starting stage: deploy_mock_nodes" - for port in 11111 22222 33333; do if lsof -i:$port >/dev/null 2>&1; then echo "Freeing up port $port..." fuser -k $port/tcp fi done - MOCK_NODES_DIR="$PWD/src/tests/tools/mock_qkd_nodes" - if [ -d "$MOCK_NODES_DIR" ]; then cd "$MOCK_NODES_DIR" || exit ./start.sh & MOCK_NODES_PID=$! else echo "Error: Mock QKD nodes directory '$MOCK_NODES_DIR' not found." exit 1 fi - echo "Waiting for mock nodes to be up..." - RETRY_COUNT=0 - MAX_RETRIES=15 - while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do if curl -s http://127.0.0.1:11111 > /dev/null && \ curl -s http://127.0.0.1:22222 > /dev/null && \ curl -s http://127.0.0.1:33333 > /dev/null; then echo "Mock nodes are up!" break else echo "Mock nodes not ready, retrying in 5 seconds..." RETRY_COUNT=$((RETRY_COUNT + 1)) sleep 5 fi done - if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then echo "Error: Mock nodes failed to start after multiple attempts." exit 1 fi # Run QKD Bootstrap Test - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose service/tests/qkd/test_functional_bootstrap.py" coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' after_script: # Check status after the tests Loading
src/device/tests/qkd/unit/descriptorQKD_links.json→src/service/tests/qkd/descriptorQKD_links.json +20 −24 Original line number Diff line number Diff line Loading @@ -10,68 +10,64 @@ "device_id": {"device_uuid": {"uuid": "QKD1"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "11111"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} }, { "device_id": {"device_uuid": {"uuid": "QKD2"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "22222"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} }, { "device_id": {"device_uuid": {"uuid": "QKD3"}}, "device_type": "qkd-node", "device_operational_status": 0, "device_drivers": [12], "device_endpoints": [], "device_config": {"config_rules": [ {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "10.0.2.10"}}, {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "<YOUR_MACHINE_IP>"}}, {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "33333"}}, {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": { "scheme": "http" }}} ]} } ], "links": [ { "link_id": {"link_uuid": {"uuid": "QKD1/10.0.2.10:1001==QKD2/10.0.2.10:2001"}}, "link_id": {"link_uuid": {"uuid": "QKD1/<YOUR_MACHINE_IP>:1001==QKD2/<YOUR_MACHINE_IP>:2001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "10.0.2.10:1001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2001"}} {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:1001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD2/10.0.2.10:2001==QKD1/10.0.2.10:1001"}}, "link_id": {"link_uuid": {"uuid": "QKD2/<YOUR_MACHINE_IP>:2001==QKD1/<YOUR_MACHINE_IP>:1001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2001"}}, {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "10.0.2.10:1001"}} {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2001"}}, {"device_id": {"device_uuid": {"uuid": "QKD1"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:1001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD2/10.0.2.10:2002==QKD3/10.0.2.10:3001"}}, "link_id": {"link_uuid": {"uuid": "QKD2/<YOUR_MACHINE_IP>:2002==QKD3/<YOUR_MACHINE_IP>:3001"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2002"}}, {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "10.0.2.10:3001"}} {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2002"}}, {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:3001"}} ] }, { "link_id": {"link_uuid": {"uuid": "QKD3/10.0.2.10:3001==QKD2/10.0.2.10:2002"}}, "link_id": {"link_uuid": {"uuid": "QKD3/<YOUR_MACHINE_IP>:3001==QKD2/<YOUR_MACHINE_IP>:2002"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "10.0.2.10:3001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "10.0.2.10:2002"}} {"device_id": {"device_uuid": {"uuid": "QKD3"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:3001"}}, {"device_id": {"device_uuid": {"uuid": "QKD2"}}, "endpoint_uuid": {"uuid": "<YOUR_MACHINE_IP>:2002"}} ] } ] } No newline at end of file
src/service/tests/qkd/test_functional_bootstrap.py 0 → 100644 +152 −0 Original line number Diff line number Diff line # Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging, os, time, json, socket, re from common.Constants import DEFAULT_CONTEXT_NAME from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum, Empty from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient from tests.Fixtures import context_client, device_client # pylint: disable=unused-import LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) # Update the path to your QKD descriptor file DESCRIPTOR_FILE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'descriptorQKD_links.json') ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) def load_descriptor_with_runtime_ip(descriptor_file_path): """ Load the descriptor file and replace placeholder IP with the machine's IP address. """ with open(descriptor_file_path, 'r') as descriptor_file: descriptor = descriptor_file.read() # Get the current machine's IP address try: # Use socket to get the local IP address directly from the network interface s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) current_ip = s.getsockname()[0] s.close() except Exception as e: raise Exception(f"Unable to get the IP address: {str(e)}") # Replace all occurrences of <YOUR_MACHINE_IP> with the current IP updated_descriptor = re.sub(r"<YOUR_MACHINE_IP>", current_ip, descriptor) # Write updated descriptor back with open(descriptor_file_path, 'w') as descriptor_file: descriptor_file.write(updated_descriptor) return json.loads(updated_descriptor) def load_and_process_descriptor(context_client, device_client, descriptor_file_path): """ Function to load and process descriptor programmatically, similar to what WebUI does. """ print(f"Loading descriptor from file: {descriptor_file_path}") try: # Update the descriptor with the runtime IP address descriptor = load_descriptor_with_runtime_ip(descriptor_file_path) # Initialize DescriptorLoader with the updated descriptor file descriptor_loader = DescriptorLoader( descriptors_file=descriptor_file_path, context_client=context_client, device_client=device_client ) # Process and validate the descriptor print("Processing the descriptor...") results = descriptor_loader.process() print(f"Descriptor processing results: {results}") print("Checking descriptor load results...") check_descriptor_load_results(results, descriptor_loader) print("Validating descriptor...") descriptor_loader.validate() print("Descriptor validated successfully.") except Exception as e: LOGGER.error(f"Failed to load and process descriptor: {e}") raise e def test_qkd_scenario_bootstrap( context_client: ContextClient, # pylint: disable=redefined-outer-name device_client: DeviceClient, # pylint: disable=redefined-outer-name ) -> None: """ This test validates that the QKD scenario is correctly bootstrapped. """ print("Starting QKD scenario bootstrap test...") # Check if context_client and device_client are instantiated if context_client is None: print("Error: context_client is not instantiated!") else: print(f"context_client is instantiated: {context_client}") if device_client is None: print("Error: device_client is not instantiated!") else: print(f"device_client is instantiated: {device_client}") # Validate empty scenario print("Validating empty scenario...") validate_empty_scenario(context_client) # Load the descriptor load_and_process_descriptor(context_client, device_client, DESCRIPTOR_FILE_PATH) def test_qkd_devices_enabled( context_client: ContextClient, # pylint: disable=redefined-outer-name ) -> None: """ This test validates that the QKD devices are enabled. """ print("Starting QKD devices enabled test...") # Check if context_client is instantiated if context_client is None: print("Error: context_client is not instantiated!") else: print(f"context_client is instantiated: {context_client}") DEVICE_OP_STATUS_ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED num_devices = -1 num_devices_enabled, num_retry = 0, 0 while (num_devices != num_devices_enabled) and (num_retry < 10): print(f"Attempt {num_retry + 1}: Checking device status...") time.sleep(1.0) # Add a delay to allow for device enablement response = context_client.ListDevices(Empty()) num_devices = len(response.devices) print(f"Total devices found: {num_devices}") num_devices_enabled = 0 for device in response.devices: if device.device_operational_status == DEVICE_OP_STATUS_ENABLED: num_devices_enabled += 1 print(f"Devices enabled: {num_devices_enabled}/{num_devices}") num_retry += 1 # Final check to ensure all devices are enabled print(f"Final device status: {num_devices_enabled}/{num_devices} devices enabled.") assert num_devices_enabled == num_devices print("QKD devices enabled test completed.") No newline at end of file