Commit 5b7e5f6b authored by Alberto Gonzalez Barneo's avatar Alberto Gonzalez Barneo
Browse files

Added service tests

parent 0034a6b4
Loading
Loading
Loading
Loading
+24 −24
Original line number Diff line number Diff line
@@ -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'
+2 −2
Original line number Diff line number Diff line
@@ -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"
+41 −1
Original line number Diff line number Diff line
@@ -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
@@ -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
+20 −24
Original line number Diff line number Diff line
@@ -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
+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