diff --git a/src/tests/benchmark/policy/.gitignore b/src/tests/benchmark/policy/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0a3f4400d5c88b1af32c7667d69d2fdc12d5424e --- /dev/null +++ b/src/tests/benchmark/policy/.gitignore @@ -0,0 +1,2 @@ +# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc. +descriptors_real.json diff --git a/src/tests/benchmark/policy/PolicyAddService.js b/src/tests/benchmark/policy/PolicyAddService.js new file mode 100644 index 0000000000000000000000000000000000000000..708209ba01862a169dd7007a05e2ba29a198282a --- /dev/null +++ b/src/tests/benchmark/policy/PolicyAddService.js @@ -0,0 +1,72 @@ +import grpc from 'k6/net/grpc'; +import exec from "k6/execution"; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['../proto'], 'policy.proto'); + +export const data = []; +for (let i = 1; i < 2; i++) { + data.push( + { + "serviceId": { + "context_id": { + "context_uuid": {"uuid": "admin"} + }, + "service_uuid": { + "uuid": "6942d780-cfa9-4dea-a946-a8a0b3f7eab2" + } + }, + "policyRuleBasic": { + "policyRuleId": {"uuid": {"uuid": i.toString()}}, + "policyRuleState": {"policyRuleState": "POLICY_UNDEFINED"}, + "priority": 0, + "conditionList": [{"kpiId": {"kpi_id": {"uuid": "1"}}, + "numericalOperator": "POLICYRULE_CONDITION_NUMERICAL_EQUAL", + "kpiValue": {"boolVal": false} + + }], + "actionList": [{}], + "booleanOperator": "POLICYRULE_CONDITION_BOOLEAN_UNDEFINED" + } + } + ); +}; + +export const options = { + scenarios :{ + + "AddPolicy-scenario": { + executor: "shared-iterations", + vus: 1, + iterations: data.length, + maxDuration: "1h" + } + } +}; + +export default () => { + client.connect('10.1.255.198:6060', { + plaintext: true, +// timeout: 10000 + }); + + var item = data[exec.scenario.iterationInInstance]; + const response = client.invoke('policy.PolicyService/PolicyAddService', item); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; + +export function handleSummary(data) { + + return { + 'summary_add_1.json': JSON.stringify(data.metrics.grpc_req_duration.values), //the default data object + }; +} diff --git a/src/tests/benchmark/policy/PolicyDelete.js b/src/tests/benchmark/policy/PolicyDelete.js new file mode 100644 index 0000000000000000000000000000000000000000..85946837eb1123bd698f907e13415b7281a779d2 --- /dev/null +++ b/src/tests/benchmark/policy/PolicyDelete.js @@ -0,0 +1,53 @@ +import grpc from 'k6/net/grpc'; +import exec from "k6/execution"; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['../proto'], 'policy.proto'); + +export const data = []; +for (let i = 1; i < 2; i++) { + data.push( + { + "uuid": {"uuid": i.toString()} + } + ); +}; + +export const options = { + scenarios :{ + + "AddPolicy-scenario": { + executor: "shared-iterations", + vus: 1, + iterations: data.length, + maxDuration: "1h" + } + } +}; + +export default () => { + client.connect('10.1.255.198:6060', { + plaintext: true, +// timeout: 10000 + }); + + var item = data[exec.scenario.iterationInInstance]; + const response = client.invoke('policy.PolicyService/PolicyDelete', item); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; + +export function handleSummary(data) { + + return { + 'summary_delete_1.json': JSON.stringify(data.metrics.grpc_req_duration.values), //the default data object + }; +} diff --git a/src/tests/benchmark/policy/PolicyUpdateService.js b/src/tests/benchmark/policy/PolicyUpdateService.js new file mode 100644 index 0000000000000000000000000000000000000000..a3774f9dac0dec420b88e6e236e8dcd2e698e3cd --- /dev/null +++ b/src/tests/benchmark/policy/PolicyUpdateService.js @@ -0,0 +1,72 @@ +import grpc from 'k6/net/grpc'; +import exec from "k6/execution"; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['../proto'], 'policy.proto'); + +export const data = []; +for (let i = 1; i < 2; i++) { + data.push( + { + "serviceId": { + "context_id": { + "context_uuid": {"uuid": "admin"} + }, + "service_uuid": { + "uuid": "6942d780-cfa9-4dea-a946-a8a0b3f7eab2" + } + }, + "policyRuleBasic": { + "policyRuleId": {"uuid": {"uuid": i.toString()}}, + "policyRuleState": {"policyRuleState": "POLICY_UNDEFINED"}, + "priority": 0, + "conditionList": [{"kpiId": {"kpi_id": {"uuid": "1"}}, + "numericalOperator": "POLICYRULE_CONDITION_NUMERICAL_EQUAL", + "kpiValue": {"boolVal": false} + + }], + "actionList": [{}], + "booleanOperator": "POLICYRULE_CONDITION_BOOLEAN_UNDEFINED" + } + } + ); +}; + +export const options = { + scenarios :{ + + "AddPolicy-scenario": { + executor: "shared-iterations", + vus: 1, + iterations: data.length, + maxDuration: "1h" + } + } +}; + +export default () => { + client.connect('10.1.255.198:6060', { + plaintext: true, +// timeout: 10000 + }); + + var item = data[exec.scenario.iterationInInstance]; + const response = client.invoke('policy.PolicyService/PolicyUpdateService', item); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; + +export function handleSummary(data) { + + return { + 'summary_add_1.json': JSON.stringify(data.metrics.grpc_req_duration.values), //the default data object + }; +} diff --git a/src/tests/benchmark/policy/README.md b/src/tests/benchmark/policy/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8b5b2a01efc357b5d8eca6a6890b051b4ffac260 --- /dev/null +++ b/src/tests/benchmark/policy/README.md @@ -0,0 +1,17 @@ + +# Grafana k6 load testing tool + +# K6 Installation Instructions on Ubuntu + +sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69 +echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list +sudo apt-get update +sudo apt-get install k6 + +Or install k6 via snap: + +sudo apt install snapd +sudo snap install k6 + +# Running K6 +k6 run script.js \ No newline at end of file diff --git a/src/tests/benchmark/policy/__init__.py b/src/tests/benchmark/policy/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..70a33251242c51f49140e596b8208a19dd5245f7 --- /dev/null +++ b/src/tests/benchmark/policy/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + diff --git a/src/tests/benchmark/policy/deploy_specs.sh b/src/tests/benchmark/policy/deploy_specs.sh new file mode 100644 index 0000000000000000000000000000000000000000..ffd91da35186fe21f418950493ef797a9af1b522 --- /dev/null +++ b/src/tests/benchmark/policy/deploy_specs.sh @@ -0,0 +1,26 @@ +# Set the URL of your local Docker registry where the images will be uploaded to. +export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/" + +# Set the list of components, separated by spaces, you want to build images for, and deploy. +# Supported components are: +# context device automation policy service compute monitoring webui +# interdomain slice pathcomp dlt +# dbscanserving opticalattackmitigator opticalattackdetector +# l3_attackmitigator l3_centralizedattackdetector l3_distributedattackdetector +export TFS_COMPONENTS="context device automation monitoring pathcomp service slice compute webui" + +# Set the tag you want to use for your images. +export TFS_IMAGE_TAG="dev" + +# Set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE="tfs" + +# Set additional manifest files to be applied after the deployment +export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml" + +# Set the new Grafana admin password +export TFS_GRAFANA_PASSWORD="admin123+" + +# If not already set, disable skip-build flag. +# If TFS_SKIP_BUILD is "YES", the containers are not rebuilt-retagged-repushed and existing ones are used. +export TFS_SKIP_BUILD=${TFS_SKIP_BUILD:-""} diff --git a/src/tests/benchmark/policy/descriptors_emulated.json b/src/tests/benchmark/policy/descriptors_emulated.json new file mode 100644 index 0000000000000000000000000000000000000000..a71d454f41f324cabb48a023d6d840a59245800c --- /dev/null +++ b/src/tests/benchmark/policy/descriptors_emulated.json @@ -0,0 +1,121 @@ +{ + "contexts": [ + { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "topology_ids": [], + "service_ids": [] + } + ], + "topologies": [ + { + "topology_id": {"topology_uuid": {"uuid": "admin"}, "context_id": {"context_uuid": {"uuid": "admin"}}}, + "device_ids": [ + {"device_uuid": {"uuid": "R1-EMU"}}, + {"device_uuid": {"uuid": "R2-EMU"}}, + {"device_uuid": {"uuid": "R3-EMU"}}, + {"device_uuid": {"uuid": "R4-EMU"}}, + {"device_uuid": {"uuid": "O1-OLS"}} + ], + "link_ids": [ + {"link_uuid": {"uuid": "R1-EMU/13/0/0==O1-OLS/aade6001-f00b-5e2f-a357-6a0a9d3de870"}}, + {"link_uuid": {"uuid": "R2-EMU/13/0/0==O1-OLS/eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}}, + {"link_uuid": {"uuid": "R3-EMU/13/0/0==O1-OLS/0ef74f99-1acc-57bd-ab9d-4b958b06c513"}}, + {"link_uuid": {"uuid": "R4-EMU/13/0/0==O1-OLS/50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}} + ] + } + ], + "devices": [ + { + "device_id": {"device_uuid": {"uuid": "R1-EMU"}}, "device_type": "emu-packet-router", + "device_operational_status": 1, "device_drivers": [0], "device_endpoints": [], + "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "13/0/0", "type": "optical", "sample_types": []}, + {"uuid": "13/1/2", "type": "copper", "sample_types": [101, 102, 201, 202]} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R2-EMU"}}, "device_type": "emu-packet-router", + "device_operational_status": 1, "device_drivers": [0], "device_endpoints": [], + "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "13/0/0", "type": "optical", "sample_types": []}, + {"uuid": "13/1/2", "type": "copper", "sample_types": [101, 102, 201, 202]} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R3-EMU"}}, "device_type": "emu-packet-router", + "device_operational_status": 1, "device_drivers": [0], "device_endpoints": [], + "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "13/0/0", "type": "optical", "sample_types": []}, + {"uuid": "13/1/2", "type": "copper", "sample_types": [101, 102, 201, 202]} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R4-EMU"}}, "device_type": "emu-packet-router", + "device_operational_status": 1, "device_drivers": [0], "device_endpoints": [], + "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "13/0/0", "type": "optical", "sample_types": []}, + {"uuid": "13/1/2", "type": "copper", "sample_types": [101, 102, 201, 202]} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "device_type": "emu-open-line-system", + "device_operational_status": 1, "device_drivers": [0], "device_endpoints": [], + "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "aade6001-f00b-5e2f-a357-6a0a9d3de870", "type": "optical", "sample_types": []}, + {"uuid": "eb287d83-f05e-53ec-ab5a-adf6bd2b5418", "type": "optical", "sample_types": []}, + {"uuid": "0ef74f99-1acc-57bd-ab9d-4b958b06c513", "type": "optical", "sample_types": []}, + {"uuid": "50296d99-58cc-5ce7-82f5-fc8ee4eec2ec", "type": "optical", "sample_types": []} + ]}}} + ]} + } + ], + "links": [ + { + "link_id": {"link_uuid": {"uuid": "R1-EMU/13/0/0==O1-OLS/aade6001-f00b-5e2f-a357-6a0a9d3de870"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}}, + {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "aade6001-f00b-5e2f-a357-6a0a9d3de870"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R2-EMU/13/0/0==O1-OLS/eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R2-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}}, + {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R3-EMU/13/0/0==O1-OLS/0ef74f99-1acc-57bd-ab9d-4b958b06c513"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R3-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}}, + {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "0ef74f99-1acc-57bd-ab9d-4b958b06c513"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R4-EMU/13/0/0==O1-OLS/50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R4-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}}, + {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}} + ] + } + ] +} \ No newline at end of file diff --git a/src/tests/benchmark/policy/run_test_01_bootstrap.sh b/src/tests/benchmark/policy/run_test_01_bootstrap.sh new file mode 100755 index 0000000000000000000000000000000000000000..10b18257b937a5aae82a66cd5e3df83abd44e1d8 --- /dev/null +++ b/src/tests/benchmark/policy/run_test_01_bootstrap.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +source tfs_runtime_env_vars.sh +pytest --verbose --log-level=INFO -o log_cli=true -o log_cli_level=INFO src/tests/benchmark/policy/tests/test_functional_bootstrap.py diff --git a/src/tests/benchmark/policy/run_test_02_create_service.sh b/src/tests/benchmark/policy/run_test_02_create_service.sh new file mode 100755 index 0000000000000000000000000000000000000000..69ef34ff954d550fbe2c22719f0afb2eb3360525 --- /dev/null +++ b/src/tests/benchmark/policy/run_test_02_create_service.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +source tfs_runtime_env_vars.sh +pytest --verbose --log-level=INFO -o log_cli=true -o log_cli_level=INFO src/tests/benchmark/policy/tests/test_functional_create_service.py diff --git a/src/tests/benchmark/policy/run_test_03_delete_service.sh b/src/tests/benchmark/policy/run_test_03_delete_service.sh new file mode 100755 index 0000000000000000000000000000000000000000..01eb521310053b06538c91cbfaae80aa3b2fdd45 --- /dev/null +++ b/src/tests/benchmark/policy/run_test_03_delete_service.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +source tfs_runtime_env_vars.sh +pytest --verbose --log-level=INFO -o log_cli=true -o log_cli_level=INFO src/tests/benchmark/policy/tests/test_functional_delete_service.py diff --git a/src/tests/benchmark/policy/run_test_04_cleanup.sh b/src/tests/benchmark/policy/run_test_04_cleanup.sh new file mode 100755 index 0000000000000000000000000000000000000000..a2be265de04552cbebe83decba538656232bf904 --- /dev/null +++ b/src/tests/benchmark/policy/run_test_04_cleanup.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +source tfs_runtime_env_vars.sh +pytest --verbose --log-level=INFO -o log_cli=true -o log_cli_level=INFO src/tests/benchmark/policy/tests/test_functional_cleanup.py diff --git a/src/tests/benchmark/policy/tests/.gitignore b/src/tests/benchmark/policy/tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..76cb708d1b532c9b69166e55f36bcb912fd5e370 --- /dev/null +++ b/src/tests/benchmark/policy/tests/.gitignore @@ -0,0 +1,2 @@ +# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc. +Credentials.py diff --git a/src/tests/benchmark/policy/tests/Fixtures.py b/src/tests/benchmark/policy/tests/Fixtures.py new file mode 100644 index 0000000000000000000000000000000000000000..3b35a12e299ba776e909fbdd2739e971431083a6 --- /dev/null +++ b/src/tests/benchmark/policy/tests/Fixtures.py @@ -0,0 +1,28 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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 pytest, logging +from common.Settings import get_setting +from tests.tools.mock_osm.Constants import WIM_PASSWORD, WIM_USERNAME +from tests.tools.mock_osm.MockOSM import MockOSM +from .Objects import WIM_MAPPING + +LOGGER = logging.getLogger(__name__) + +@pytest.fixture(scope='session') +def osm_wim(): + wim_url = 'http://{:s}:{:s}'.format( + get_setting('COMPUTESERVICE_SERVICE_HOST'), str(get_setting('COMPUTESERVICE_SERVICE_PORT_HTTP'))) + LOGGER.info('WIM_MAPPING = {:s}'.format(str(WIM_MAPPING))) + return MockOSM(wim_url, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD) diff --git a/src/tests/benchmark/policy/tests/Objects.py b/src/tests/benchmark/policy/tests/Objects.py new file mode 100644 index 0000000000000000000000000000000000000000..7bfbe9fce558d6a86d965ecb6421369d7f544d4d --- /dev/null +++ b/src/tests/benchmark/policy/tests/Objects.py @@ -0,0 +1,38 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +from common.tools.object_factory.Device import json_device_id +from common.tools.object_factory.EndPoint import json_endpoint_id +from tests.tools.mock_osm.Tools import connection_point, wim_mapping + +# ----- WIM Service Settings ------------------------------------------------------------------------------------------- + +WIM_DC1_SITE_ID = '1' +WIM_DC1_DEVICE_ID = json_device_id('R1-EMU') +WIM_DC1_ENDPOINT_ID = json_endpoint_id(WIM_DC1_DEVICE_ID, '13/1/2') + +WIM_DC2_SITE_ID = '2' +WIM_DC2_DEVICE_ID = json_device_id('R3-EMU') +WIM_DC2_ENDPOINT_ID = json_endpoint_id(WIM_DC2_DEVICE_ID, '13/1/2') + +WIM_SEP_DC1, WIM_MAP_DC1 = wim_mapping(WIM_DC1_SITE_ID, WIM_DC1_ENDPOINT_ID) +WIM_SEP_DC2, WIM_MAP_DC2 = wim_mapping(WIM_DC2_SITE_ID, WIM_DC2_ENDPOINT_ID) +WIM_MAPPING = [WIM_MAP_DC1, WIM_MAP_DC2] + +WIM_SRV_VLAN_ID = 300 +WIM_SERVICE_TYPE = 'ELINE' +WIM_SERVICE_CONNECTION_POINTS = [ + connection_point(WIM_SEP_DC1, 'dot1q', WIM_SRV_VLAN_ID), + connection_point(WIM_SEP_DC2, 'dot1q', WIM_SRV_VLAN_ID), +] diff --git a/src/tests/benchmark/policy/tests/__init__.py b/src/tests/benchmark/policy/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..70a33251242c51f49140e596b8208a19dd5245f7 --- /dev/null +++ b/src/tests/benchmark/policy/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + diff --git a/src/tests/benchmark/policy/tests/test_functional_bootstrap.py b/src/tests/benchmark/policy/tests/test_functional_bootstrap.py new file mode 100644 index 0000000000000000000000000000000000000000..71deb9d596b1494e148b140902ca927e5d664dd3 --- /dev/null +++ b/src/tests/benchmark/policy/tests/test_functional_bootstrap.py @@ -0,0 +1,95 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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, time +from common.proto.context_pb2 import ContextId, Empty +from common.proto.monitoring_pb2 import KpiDescriptorList +from common.tests.LoadScenario import load_scenario_from_descriptor +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from monitoring.client.MonitoringClient import MonitoringClient +from tests.Fixtures import context_client, device_client, monitoring_client # pylint: disable=unused-import + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DESCRIPTOR_FILE = 'ofc22/descriptors_emulated.json' + +def test_scenario_bootstrap( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name +) -> None: + # ----- List entities - Ensure database is empty ------------------------------------------------------------------- + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == 0 + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == 0 + + response = context_client.ListLinks(Empty()) + assert len(response.links) == 0 + + + # ----- Load Scenario ---------------------------------------------------------------------------------------------- + descriptor_loader = load_scenario_from_descriptor( + DESCRIPTOR_FILE, context_client, device_client, None, None) + + + # ----- List entities - Ensure scenario is ready ------------------------------------------------------------------- + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + for context_uuid, _ in descriptor_loader.num_services.items(): + response = context_client.ListServices(ContextId(**json_context_id(context_uuid))) + assert len(response.services) == 0 + +def test_scenario_kpis_created( + context_client : ContextClient, # pylint: disable=redefined-outer-name + monitoring_client: MonitoringClient, # pylint: disable=redefined-outer-name +) -> None: + """ + This test validates that KPIs related to the service/device/endpoint were created + during the service creation process. + """ + response = context_client.ListDevices(Empty()) + kpis_expected = set() + for device in response.devices: + device_uuid = device.device_id.device_uuid.uuid + for endpoint in device.device_endpoints: + endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid + for kpi_sample_type in endpoint.kpi_sample_types: + kpis_expected.add((device_uuid, endpoint_uuid, kpi_sample_type)) + num_kpis_expected = len(kpis_expected) + LOGGER.info('Num KPIs expected: {:d}'.format(num_kpis_expected)) + + num_kpis_created, num_retry = 0, 0 + while (num_kpis_created != num_kpis_expected) and (num_retry < 5): + response: KpiDescriptorList = monitoring_client.GetKpiDescriptorList(Empty()) + num_kpis_created = len(response.kpi_descriptor_list) + LOGGER.info('Num KPIs created: {:d}'.format(num_kpis_created)) + time.sleep(0.5) + num_retry += 1 + assert num_kpis_created == num_kpis_expected diff --git a/src/tests/benchmark/policy/tests/test_functional_cleanup.py b/src/tests/benchmark/policy/tests/test_functional_cleanup.py new file mode 100644 index 0000000000000000000000000000000000000000..be807eaa0242f2363b5b6c189ce4de264528a54c --- /dev/null +++ b/src/tests/benchmark/policy/tests/test_functional_cleanup.py @@ -0,0 +1,80 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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 +from common.tools.descriptor.Loader import DescriptorLoader +from common.tools.object_factory.Context import json_context_id +from common.proto.context_pb2 import ContextId, DeviceId, Empty, LinkId, TopologyId +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) + +DESCRIPTOR_FILE = 'ofc22/descriptors_emulated.json' + + +def test_services_removed( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name +) -> None: + # ----- List entities - Ensure service is removed ------------------------------------------------------------------ + with open(DESCRIPTOR_FILE, 'r', encoding='UTF-8') as f: + descriptors = f.read() + + descriptor_loader = DescriptorLoader(descriptors) + + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + for context_uuid, _ in descriptor_loader.num_services.items(): + response = context_client.ListServices(ContextId(**json_context_id(context_uuid))) + assert len(response.services) == 0 + + + # ----- Delete Links, Devices, Topologies, Contexts ---------------------------------------------------------------- + for link in descriptor_loader.links: + context_client.RemoveLink(LinkId(**link['link_id'])) + + for device in descriptor_loader.devices: + device_client .DeleteDevice(DeviceId(**device['device_id'])) + + for context_uuid, topology_list in descriptor_loader.topologies.items(): + for topology in topology_list: + context_client.RemoveTopology(TopologyId(**topology['topology_id'])) + + for context in descriptor_loader.contexts: + context_client.RemoveContext(ContextId(**context['context_id'])) + + + # ----- List entities - Ensure database is empty again ------------------------------------------------------------- + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == 0 + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == 0 + + response = context_client.ListLinks(Empty()) + assert len(response.links) == 0 diff --git a/src/tests/benchmark/policy/tests/test_functional_create_service.py b/src/tests/benchmark/policy/tests/test_functional_create_service.py new file mode 100644 index 0000000000000000000000000000000000000000..e606d060d52631ba72e191d7c025bd7b43048b39 --- /dev/null +++ b/src/tests/benchmark/policy/tests/test_functional_create_service.py @@ -0,0 +1,124 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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, random +from common.DeviceTypes import DeviceTypeEnum +from common.proto.context_pb2 import ContextId, Empty +from common.proto.kpi_sample_types_pb2 import KpiSampleType +from common.tools.descriptor.Loader import DescriptorLoader +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from monitoring.client.MonitoringClient import MonitoringClient +from tests.Fixtures import context_client, device_client, monitoring_client # pylint: disable=unused-import +from tests.tools.mock_osm.MockOSM import MockOSM +from .Fixtures import osm_wim # pylint: disable=unused-import +from .Objects import WIM_SERVICE_CONNECTION_POINTS, WIM_SERVICE_TYPE + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DEVTYPE_EMU_PR = DeviceTypeEnum.EMULATED_PACKET_ROUTER.value +DEVTYPE_EMU_OLS = DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value + +DESCRIPTOR_FILE = 'ofc22/descriptors_emulated.json' + +def test_service_creation(context_client : ContextClient, osm_wim : MockOSM): # pylint: disable=redefined-outer-name + # ----- List entities - Ensure scenario is ready ------------------------------------------------------------------- + with open(DESCRIPTOR_FILE, 'r', encoding='UTF-8') as f: + descriptors = f.read() + + descriptor_loader = DescriptorLoader(descriptors) + + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + for context_uuid, num_services in descriptor_loader.num_services.items(): + response = context_client.ListServices(ContextId(**json_context_id(context_uuid))) + assert len(response.services) == 0 + + + # ----- Create Service --------------------------------------------------------------------------------------------- + service_uuid = osm_wim.create_connectivity_service(WIM_SERVICE_TYPE, WIM_SERVICE_CONNECTION_POINTS) + osm_wim.get_connectivity_service_status(service_uuid) + + + # ----- List entities - Ensure service is created ------------------------------------------------------------------ + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + for context_uuid, num_services in descriptor_loader.num_services.items(): + response = context_client.ListServices(ContextId(**json_context_id(context_uuid))) + LOGGER.info('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response))) + assert len(response.services) == 2*num_services # OLS & L3NM => (L3NM + TAPI) + + for service in response.services: + service_id = service.service_id + response = context_client.ListConnections(service_id) + LOGGER.info(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response))) + assert len(response.connections) == 1 # one connection per service + + +def test_scenario_kpi_values_created( + monitoring_client: MonitoringClient, # pylint: disable=redefined-outer-name +) -> None: + """ + This test validates that KPI values have been inserted into the monitoring database. + We short k KPI descriptors to test. + """ + response = monitoring_client.GetKpiDescriptorList(Empty()) + kpi_descriptors = random.choices(response.kpi_descriptor_list, k=2) + + for kpi_descriptor in kpi_descriptors: + MSG = 'KPI(kpi_uuid={:s}, device_uuid={:s}, endpoint_uuid={:s}, service_uuid={:s}, kpi_sample_type={:s})...' + LOGGER.info(MSG.format( + str(kpi_descriptor.kpi_id.kpi_id.uuid), str(kpi_descriptor.device_id.device_uuid.uuid), + str(kpi_descriptor.endpoint_id.endpoint_uuid.uuid), str(kpi_descriptor.service_id.service_uuid.uuid), + str(KpiSampleType.Name(kpi_descriptor.kpi_sample_type)))) + response = monitoring_client.GetInstantKpi(kpi_descriptor.kpi_id) + kpi_uuid = response.kpi_id.kpi_id.uuid + assert kpi_uuid == kpi_descriptor.kpi_id.kpi_id.uuid + kpi_value_type = response.kpi_value.WhichOneof('value') + if kpi_value_type is None: + MSG = ' KPI({:s}): No instant value found' + LOGGER.warning(MSG.format(str(kpi_uuid))) + else: + kpi_timestamp = response.timestamp.timestamp + assert kpi_timestamp > 0 + assert kpi_value_type == 'floatVal' + kpi_value = getattr(response.kpi_value, kpi_value_type) + MSG = ' KPI({:s}): timestamp={:s} value_type={:s} value={:s}' + LOGGER.info(MSG.format(str(kpi_uuid), str(kpi_timestamp), str(kpi_value_type), str(kpi_value))) diff --git a/src/tests/benchmark/policy/tests/test_functional_delete_service.py b/src/tests/benchmark/policy/tests/test_functional_delete_service.py new file mode 100644 index 0000000000000000000000000000000000000000..0f8d088012bed164e4603a813bfe9154eda8f568 --- /dev/null +++ b/src/tests/benchmark/policy/tests/test_functional_delete_service.py @@ -0,0 +1,99 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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 +from common.Constants import DEFAULT_CONTEXT_UUID +from common.DeviceTypes import DeviceTypeEnum +from common.proto.context_pb2 import ContextId, Empty, ServiceTypeEnum +from common.tools.descriptor.Loader import DescriptorLoader +from common.tools.object_factory.Context import json_context_id +from common.tools.grpc.Tools import grpc_message_to_json_string +from context.client.ContextClient import ContextClient +from tests.Fixtures import context_client # pylint: disable=unused-import +from tests.tools.mock_osm.MockOSM import MockOSM +from .Fixtures import osm_wim # pylint: disable=unused-import + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DEVTYPE_EMU_PR = DeviceTypeEnum.EMULATED_PACKET_ROUTER.value +DEVTYPE_EMU_OLS = DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value + +DESCRIPTOR_FILE = 'ofc22/descriptors_emulated.json' + + +def test_service_removal(context_client : ContextClient, osm_wim : MockOSM): # pylint: disable=redefined-outer-name + # ----- List entities - Ensure service is created ------------------------------------------------------------------ + with open(DESCRIPTOR_FILE, 'r', encoding='UTF-8') as f: + descriptors = f.read() + + descriptor_loader = DescriptorLoader(descriptors) + + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + l3nm_service_uuids = set() + response = context_client.ListServices(ContextId(**json_context_id(DEFAULT_CONTEXT_UUID))) + assert len(response.services) == 2 # OLS & L3NM => (L3NM + TAPI) + for service in response.services: + service_id = service.service_id + + if service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM: + service_uuid = service_id.service_uuid.uuid + l3nm_service_uuids.add(service_uuid) + osm_wim.conn_info[service_uuid] = {} + + response = context_client.ListConnections(service_id) + LOGGER.info(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response))) + assert len(response.connections) == 1 # one connection per service + + # Identify service to delete + assert len(l3nm_service_uuids) == 1 # assume a single L3NM service has been created + l3nm_service_uuid = set(l3nm_service_uuids).pop() + + + # ----- Delete Service --------------------------------------------------------------------------------------------- + osm_wim.delete_connectivity_service(l3nm_service_uuid) + + + # ----- List entities - Ensure service is removed ------------------------------------------------------------------ + response = context_client.ListContexts(Empty()) + assert len(response.contexts) == descriptor_loader.num_contexts + + for context_uuid, num_topologies in descriptor_loader.num_topologies.items(): + response = context_client.ListTopologies(ContextId(**json_context_id(context_uuid))) + assert len(response.topologies) == num_topologies + + response = context_client.ListDevices(Empty()) + assert len(response.devices) == descriptor_loader.num_devices + + response = context_client.ListLinks(Empty()) + assert len(response.links) == descriptor_loader.num_links + + for context_uuid, num_services in descriptor_loader.num_services.items(): + response = context_client.ListServices(ContextId(**json_context_id(context_uuid))) + assert len(response.services) == 0