From a73a2465241cefc29f23f90257517ae96b5dc1e1 Mon Sep 17 00:00:00 2001 From: jordlay <72226943+jordlay@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:12:58 +0000 Subject: [PATCH] Improve Unit Testing (#152) * moved working tests to new folder structure; added empty tests for processors and build * added empty generate cofnig tests; fixed and moved bicep,artifact and definitino folder builder tests * added nexus arm tests; removed outdated vnf mocks * added azure core tests for every function (including base) * fixed up core and nexus arm processor * fixed up arm processors; added logging to tests * added arm template tests * added test from copilot learning day * changed assert * removed build folder; added json dump to artifact and definition tests; improved arm processor testing * removed mock open and replaced with new templates * fixed linting --------- Co-authored-by: Jordan --- .../onboarding_core_vnf_handler.py | 3 +- .../onboarding_nexus_vnf_handler.py | 1 - .../cli_handlers/onboarding_vnf_handler.py | 7 +- src/aosm/azext_aosm/common/utils.py | 3 +- .../reader/artifact_definition.py | 2 +- src/aosm/azext_aosm/inputs/vhd_file_input.py | 2 +- .../no-params-template.json | 96 ++++++++++ .../mock_arm_templates/simple-template.json | 102 +++++++++++ .../ubuntu-template.json | 0 .../input_with_filepath.json | 18 -- .../mock_vnf_OUTDATED/input_with_fp.json | 18 -- .../mock_vnf_OUTDATED/input_with_sas.json | 21 --- .../input_with_sas_token.json | 21 --- .../test_artifact_definition.py | 12 +- .../test_bicep_definition.py | 0 .../test_core_vnf_build.py} | 0 .../test_definition_folder.py | 0 .../test_nexus_vnf_build.py} | 0 .../test_nsd_cli_generate_config.py} | 0 .../test_definition_folder_builder.py | 48 ----- .../test_artifact_builder.py | 7 +- .../test_bicep_builder.py | 0 .../test_definition_folder_builder.py | 52 ++++++ .../test_cnf_generate_config.py | 0 .../test_core_vnf_generate_config.py | 0 .../test_nexus_vnf_generate_config.py | 0 .../test_nsd_generate_config.py | 0 .../test_inputs/test_arm_template_input.py | 170 +++++++++++++++++ .../test_helm_chart_input.py | 46 ++++- .../test_core_arm_processor.py | 173 ++++++++++++++++++ .../test_helm_chart_processor.py | 2 +- .../test_nexus_arm_processor.py | 173 ++++++++++++++++-- .../test_nexus_image_processor.py | 0 .../test_processors/test_vhd_processor.py | 0 .../tests/latest/unit_test/test_utils.py | 0 35 files changed, 820 insertions(+), 157 deletions(-) create mode 100644 src/aosm/azext_aosm/tests/latest/mock_arm_templates/no-params-template.json create mode 100644 src/aosm/azext_aosm/tests/latest/mock_arm_templates/simple-template.json rename src/aosm/azext_aosm/tests/latest/{mock_vnf_OUTDATED => mock_arm_templates}/ubuntu-template.json (100%) delete mode 100644 src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_filepath.json delete mode 100644 src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_fp.json delete mode 100644 src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas.json delete mode 100644 src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas_token.json rename src/aosm/azext_aosm/tests/latest/unit_test/{ => broken_tests}/test_artifact_definition.py (87%) rename src/aosm/azext_aosm/tests/latest/unit_test/{ => broken_tests}/test_bicep_definition.py (100%) rename src/aosm/azext_aosm/tests/latest/unit_test/{test_core_vnf_handler.py => broken_tests/test_core_vnf_build.py} (100%) rename src/aosm/azext_aosm/tests/latest/unit_test/{ => broken_tests}/test_definition_folder.py (100%) rename src/aosm/azext_aosm/tests/latest/unit_test/{test_nexus_vnf_handler.py => broken_tests/test_nexus_vnf_build.py} (100%) rename src/aosm/azext_aosm/tests/latest/unit_test/{test_nsd_cli_handler.py => broken_tests/test_nsd_cli_generate_config.py} (100%) delete mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder_builder.py rename src/aosm/azext_aosm/tests/latest/unit_test/{ => test_definiton_folder_builder}/test_artifact_builder.py (87%) rename src/aosm/azext_aosm/tests/latest/unit_test/{ => test_definiton_folder_builder}/test_bicep_builder.py (100%) create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_definition_folder_builder.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_cnf_generate_config.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_core_vnf_generate_config.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nexus_vnf_generate_config.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nsd_generate_config.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_arm_template_input.py rename src/aosm/azext_aosm/tests/latest/unit_test/{ => test_inputs}/test_helm_chart_input.py (69%) create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_core_arm_processor.py rename src/aosm/azext_aosm/tests/latest/unit_test/{ => test_processors}/test_helm_chart_processor.py (99%) create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_image_processor.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_vhd_processor.py create mode 100644 src/aosm/azext_aosm/tests/latest/unit_test/test_utils.py diff --git a/src/aosm/azext_aosm/cli_handlers/onboarding_core_vnf_handler.py b/src/aosm/azext_aosm/cli_handlers/onboarding_core_vnf_handler.py index 44aeef92b41..270484761be 100644 --- a/src/aosm/azext_aosm/cli_handlers/onboarding_core_vnf_handler.py +++ b/src/aosm/azext_aosm/cli_handlers/onboarding_core_vnf_handler.py @@ -11,7 +11,6 @@ from azext_aosm.build_processors.arm_processor import AzureCoreArmBuildProcessor from azext_aosm.build_processors.vhd_processor import VHDProcessor -from azext_aosm.build_processors.base_processor import BaseInputProcessor from azext_aosm.common.constants import ( BASE_FOLDER_NAME, VNF_CORE_BASE_TEMPLATE_FILENAME, @@ -146,7 +145,7 @@ def _get_default_config(self, vhd) -> Dict[str, Any]: default_config.update({"image_hyper_v_generation": "V1"}) if vhd.image_api_version: default_config.update({"image_api_version": vhd.image_api_version}) - + # Add imageName default_config["imageName"] = self.config.nf_name + 'Image' return default_config diff --git a/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py b/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py index 9be8928cb87..b925ae104b8 100644 --- a/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py +++ b/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py @@ -11,7 +11,6 @@ from azext_aosm.build_processors.arm_processor import NexusArmBuildProcessor from azext_aosm.build_processors.nexus_image_processor import NexusImageProcessor -from azext_aosm.build_processors.base_processor import BaseInputProcessor from azext_aosm.common.constants import ( BASE_FOLDER_NAME, VNF_TEMPLATE_FOLDER_NAME, diff --git a/src/aosm/azext_aosm/cli_handlers/onboarding_vnf_handler.py b/src/aosm/azext_aosm/cli_handlers/onboarding_vnf_handler.py index 5ed33c14336..0d17dc700a9 100644 --- a/src/aosm/azext_aosm/cli_handlers/onboarding_vnf_handler.py +++ b/src/aosm/azext_aosm/cli_handlers/onboarding_vnf_handler.py @@ -9,11 +9,10 @@ from .onboarding_nfd_base_handler import OnboardingNFDBaseCLIHandler from knack.log import get_logger -# from azext_aosm.configuration_models.onboarding_vnf_input_config import ( -# OnboardingBaseVNFInputConfig, -# ) from azext_aosm.common.utils import render_bicep_contents_from_j2, get_template_path -from azext_aosm.configuration_models.onboarding_vnf_input_config import (OnboardingCoreVNFInputConfig, OnboardingNexusVNFInputConfig) +from azext_aosm.configuration_models.onboarding_vnf_input_config import ( + OnboardingCoreVNFInputConfig, OnboardingNexusVNFInputConfig +) from azext_aosm.definition_folder.builder.bicep_builder import ( BicepDefinitionElementBuilder, ) diff --git a/src/aosm/azext_aosm/common/utils.py b/src/aosm/azext_aosm/common/utils.py index 025fa8c8030..8db57006db9 100644 --- a/src/aosm/azext_aosm/common/utils.py +++ b/src/aosm/azext_aosm/common/utils.py @@ -5,6 +5,7 @@ import re import os import tarfile +from typing import Tuple from pathlib import Path from jinja2 import StrictUndefined, Template import json @@ -125,7 +126,7 @@ def check_tool_installed(tool_name: str) -> None: raise MissingDependency(f"You must install {tool_name} to use this command.") -def split_image_path(image) -> "tuple[str, str, str]": +def split_image_path(image) -> Tuple[str, str, str]: """Split the image path into source acr registry, name and version.""" (source_acr_registry, name_and_version) = image.split("/", 2) (name, version) = name_and_version.split(":", 2) diff --git a/src/aosm/azext_aosm/definition_folder/reader/artifact_definition.py b/src/aosm/azext_aosm/definition_folder/reader/artifact_definition.py index 37004859ffc..30e08393ba9 100644 --- a/src/aosm/azext_aosm/definition_folder/reader/artifact_definition.py +++ b/src/aosm/azext_aosm/definition_folder/reader/artifact_definition.py @@ -40,7 +40,7 @@ def create_artifact_object(artifact: dict) -> BaseArtifact: """ if "type" not in artifact or artifact["type"] not in ARTIFACT_TYPE_TO_CLASS: raise ValueError( - "Artifact type is missing or invalid for artifact {artifact}" + f"Artifact type is missing or invalid for artifact {artifact}" ) # Use reflection to get the required fields for the artifact class class_sig = inspect.signature(ARTIFACT_TYPE_TO_CLASS[artifact["type"]].__init__) diff --git a/src/aosm/azext_aosm/inputs/vhd_file_input.py b/src/aosm/azext_aosm/inputs/vhd_file_input.py index 566a5d6c1bf..d2eab8af48a 100644 --- a/src/aosm/azext_aosm/inputs/vhd_file_input.py +++ b/src/aosm/azext_aosm/inputs/vhd_file_input.py @@ -92,4 +92,4 @@ def get_schema(self) -> Dict[str, Any]: schema["required"] += vhd_required logger.debug("Schema for VHD file input: %s", json.dumps(schema, indent=4)) - return copy.deepcopy(schema) \ No newline at end of file + return copy.deepcopy(schema) diff --git a/src/aosm/azext_aosm/tests/latest/mock_arm_templates/no-params-template.json b/src/aosm/azext_aosm/tests/latest/mock_arm_templates/no-params-template.json new file mode 100644 index 00000000000..c61fdffc7af --- /dev/null +++ b/src/aosm/azext_aosm/tests/latest/mock_arm_templates/no-params-template.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "1656082395923655778" + } + }, + "variables": { + "imageResourceGroup": "[resourceGroup().name]", + "subscriptionId": "[subscription().subscriptionId]", + "vmSizeSku": "Standard_D2s_v3" + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-05-01", + "name": "[format('{0}_nic', parameters('ubuntuVmName'))]", + "location": "[parameters('location')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[format('{0}/subnets/{1}', parameters('virtualNetworkId'), parameters('subnetName'))]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-07-01", + "name": "[parameters('ubuntuVmName')]", + "location": "[parameters('location')]", + "properties": { + "hardwareProfile": { + "vmSize": "[variables('vmSizeSku')]" + }, + "storageProfile": { + "imageReference": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('imageResourceGroup')), 'Microsoft.Compute/images', parameters('imageName'))]" + }, + "osDisk": { + "osType": "Linux", + "name": "[format('{0}_disk', parameters('ubuntuVmName'))]", + "createOption": "FromImage", + "caching": "ReadWrite", + "writeAcceleratorEnabled": false, + "managedDisk": "[json('{\"storageAccountType\": \"Premium_LRS\"}')]", + "deleteOption": "Delete", + "diskSizeGB": 30 + } + }, + "osProfile": { + "computerName": "[parameters('ubuntuVmName')]", + "adminUsername": "azureuser", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "/home/azureuser/.ssh/authorized_keys", + "keyData": "[parameters('sshPublicKeyAdmin')]" + } + ] + }, + "provisionVMAgent": true, + "patchSettings": { + "patchMode": "ImageDefault", + "assessmentMode": "ImageDefault" + } + }, + "secrets": [], + "allowExtensionOperations": true + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('{0}_nic', parameters('ubuntuVmName')))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('{0}_nic', parameters('ubuntuVmName')))]" + ] + } + ] +} \ No newline at end of file diff --git a/src/aosm/azext_aosm/tests/latest/mock_arm_templates/simple-template.json b/src/aosm/azext_aosm/tests/latest/mock_arm_templates/simple-template.json new file mode 100644 index 00000000000..be76c072039 --- /dev/null +++ b/src/aosm/azext_aosm/tests/latest/mock_arm_templates/simple-template.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "1656082395923655778" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + } + }, + "variables": { + "imageResourceGroup": "[resourceGroup().name]", + "subscriptionId": "[subscription().subscriptionId]", + "vmSizeSku": "Standard_D2s_v3" + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2021-05-01", + "name": "[format('{0}_nic', parameters('ubuntuVmName'))]", + "location": "[parameters('location')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "subnet": { + "id": "[format('{0}/subnets/{1}', parameters('virtualNetworkId'), parameters('subnetName'))]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2021-07-01", + "name": "[parameters('ubuntuVmName')]", + "location": "[parameters('location')]", + "properties": { + "hardwareProfile": { + "vmSize": "[variables('vmSizeSku')]" + }, + "storageProfile": { + "imageReference": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('imageResourceGroup')), 'Microsoft.Compute/images', parameters('imageName'))]" + }, + "osDisk": { + "osType": "Linux", + "name": "[format('{0}_disk', parameters('ubuntuVmName'))]", + "createOption": "FromImage", + "caching": "ReadWrite", + "writeAcceleratorEnabled": false, + "managedDisk": "[json('{\"storageAccountType\": \"Premium_LRS\"}')]", + "deleteOption": "Delete", + "diskSizeGB": 30 + } + }, + "osProfile": { + "computerName": "[parameters('ubuntuVmName')]", + "adminUsername": "azureuser", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "/home/azureuser/.ssh/authorized_keys", + "keyData": "[parameters('sshPublicKeyAdmin')]" + } + ] + }, + "provisionVMAgent": true, + "patchSettings": { + "patchMode": "ImageDefault", + "assessmentMode": "ImageDefault" + } + }, + "secrets": [], + "allowExtensionOperations": true + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('{0}_nic', parameters('ubuntuVmName')))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('{0}_nic', parameters('ubuntuVmName')))]" + ] + } + ] +} \ No newline at end of file diff --git a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/ubuntu-template.json b/src/aosm/azext_aosm/tests/latest/mock_arm_templates/ubuntu-template.json similarity index 100% rename from src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/ubuntu-template.json rename to src/aosm/azext_aosm/tests/latest/mock_arm_templates/ubuntu-template.json diff --git a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_filepath.json b/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_filepath.json deleted file mode 100644 index b3a3b991a1d..00000000000 --- a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_filepath.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "publisher_name": "jamie-mobile-publisher", - "publisher_resource_group_name": "Jamie-publisher", - "nf_name": "ubuntu-vm", - "version": "1.0.0", - "acr_artifact_store_name": "ubuntu-acr", - "location": "eastus", - "blob_artifact_store_name": "ubuntu-blob-store", - "image_name_parameter": "imageName", - "arm_template": { - "file_path": "ubuntu-template.json", - "version": "1.0.0" - }, - "vhd": { - "file_path": "livecd.ubuntu-cpc.azure.vhd", - "version": "1-0-0" - } -} diff --git a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_fp.json b/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_fp.json deleted file mode 100644 index b3a3b991a1d..00000000000 --- a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_fp.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "publisher_name": "jamie-mobile-publisher", - "publisher_resource_group_name": "Jamie-publisher", - "nf_name": "ubuntu-vm", - "version": "1.0.0", - "acr_artifact_store_name": "ubuntu-acr", - "location": "eastus", - "blob_artifact_store_name": "ubuntu-blob-store", - "image_name_parameter": "imageName", - "arm_template": { - "file_path": "ubuntu-template.json", - "version": "1.0.0" - }, - "vhd": { - "file_path": "livecd.ubuntu-cpc.azure.vhd", - "version": "1-0-0" - } -} diff --git a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas.json b/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas.json deleted file mode 100644 index 5222d940186..00000000000 --- a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "publisher_name": "jamie-mobile-publisher", - "publisher_resource_group_name": "Jamie-publisher", - "nf_name": "ubuntu-vm", - "version": "1.0.0", - "acr_artifact_store_name": "ubuntu-acr", - "location": "eastus", - "blob_artifact_store_name": "ubuntu-blob-store", - "image_name_parameter": "imageName", - "arm_template": { - "file_path": "ubuntu-template.json", - "version": "1.0.0" - }, - "vhd": { - "blob_sas_url": "https://a/dummy/sas-url", - "version": "1-0-0", - "image_disk_size_GB": 30, - "image_hyper_v_generation": "V1", - "image_api_version": "2023-03-01" - } -} \ No newline at end of file diff --git a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas_token.json b/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas_token.json deleted file mode 100644 index 5222d940186..00000000000 --- a/src/aosm/azext_aosm/tests/latest/mock_vnf_OUTDATED/input_with_sas_token.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "publisher_name": "jamie-mobile-publisher", - "publisher_resource_group_name": "Jamie-publisher", - "nf_name": "ubuntu-vm", - "version": "1.0.0", - "acr_artifact_store_name": "ubuntu-acr", - "location": "eastus", - "blob_artifact_store_name": "ubuntu-blob-store", - "image_name_parameter": "imageName", - "arm_template": { - "file_path": "ubuntu-template.json", - "version": "1.0.0" - }, - "vhd": { - "blob_sas_url": "https://a/dummy/sas-url", - "version": "1-0-0", - "image_disk_size_GB": 30, - "image_hyper_v_generation": "V1", - "image_api_version": "2023-03-01" - } -} \ No newline at end of file diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_definition.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_artifact_definition.py similarity index 87% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_definition.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_artifact_definition.py index d5bc61db968..e410269764d 100644 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_definition.py +++ b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_artifact_definition.py @@ -23,13 +23,17 @@ # mock_read_text.return_value = """ # [ # { +# "artifact_type": "ArmTemplate", +# "artifact_name": "abc", +# "artifact_version": "1.0.0", # "type": "MockType1", -# "artifact_manifest": "def", # "file_path": "def" # }, # { +# "artifact_type": "ArmTemplate", +# "artifact_name": "ghi", +# "artifact_version": "2.1.1", # "type": "MockType2", -# "artifact_manifest": "jkl", # "file_path": "jkl" # } # ] @@ -52,7 +56,9 @@ # definition_element = ArtifactDefinitionElement(element_path, False) # # Deploy the element. -# definition_element.deploy() +# mock_config = MagicMock() +# mock_context = MagicMock() +# definition_element.deploy(config=mock_config, command_context=mock_context) # # Check results. # mock_type_1.assert_has_calls( diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_bicep_definition.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_bicep_definition.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_bicep_definition.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_bicep_definition.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_core_vnf_handler.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_core_vnf_build.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_core_vnf_handler.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_core_vnf_build.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_definition_folder.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_definition_folder.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_nexus_vnf_handler.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_nexus_vnf_build.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_nexus_vnf_handler.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_nexus_vnf_build.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_nsd_cli_handler.py b/src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_nsd_cli_generate_config.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_nsd_cli_handler.py rename to src/aosm/azext_aosm/tests/latest/unit_test/broken_tests/test_nsd_cli_generate_config.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder_builder.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder_builder.py deleted file mode 100644 index f2f2a9b419d..00000000000 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_definition_folder_builder.py +++ /dev/null @@ -1,48 +0,0 @@ -# # -------------------------------------------------------------------------------------------- -# # Copyright (c) Microsoft Corporation. All rights reserved. -# # Licensed under the MIT License. See License.txt in the project root for license information. -# # -------------------------------------------------------------------------------------------- - -# from pathlib import Path -# from unittest import TestCase -# from unittest.mock import MagicMock, patch - -# from azext_aosm.definition_folder.builder.definition_folder_builder import DefinitionFolderBuilder - - -# class TestDefinitionFolderBuilder(TestCase): -# """Test the definition folder builder.""" - -# @patch("pathlib.Path.write_text") -# @patch("pathlib.Path.mkdir") -# def test_add_elements_and_write(self, mock_mkdir, mock_write_text): -# """Test adding elements and writing the definition folder.""" - -# # Create some mocks to act as definition elements. -# element_1 = MagicMock() -# element_1.path = Path("/some/folder/element_1") -# element_1.only_delete_on_clean = False -# element_2 = MagicMock() -# element_2.path = Path("/some/folder/element_2") -# element_2.only_delete_on_clean = True - -# # Create a definition folder builder. -# definition_folder_builder = DefinitionFolderBuilder(Path("/some/folder")) - -# # Add the elements to the definition folder builder. -# definition_folder_builder.add_element(element_1) -# definition_folder_builder.add_element(element_2) - -# # Write the definition folder. -# definition_folder_builder.write() - -# # Check that the elements were written to disk. -# mock_mkdir.assert_called_once() -# element_1.write.assert_called_once() -# element_2.write.assert_called_once() - -# # Check that the index.json file was written to disk. -# mock_write_text.assert_called_once_with( -# '[{"name": "element_1", "type": "artifact", "only_delete_on_clean": false}, ' -# '{"name": "element_2", "type": "artifact", "only_delete_on_clean": true}]' -# ) diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_builder.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_artifact_builder.py similarity index 87% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_builder.py rename to src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_artifact_builder.py index 7be432b63b6..e9c4003f0c8 100644 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_artifact_builder.py +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_artifact_builder.py @@ -2,7 +2,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- - +import json from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, patch @@ -37,5 +37,6 @@ def test_write(self, mock_mkdir, mock_write_text): mock_mkdir.assert_called_once() artifact_1.to_dict.assert_called_once() artifact_2.to_dict.assert_called_once() - mock_write_text.assert_called_once_with( - '[\n {\n "abc": "def"\n },\n {\n "ghi": "jkl"\n }\n]') + expected_params = [{"abc":"def"}, + {"ghi":"jkl"}] + mock_write_text.assert_called_once_with(json.dumps(expected_params, indent=4)) diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_bicep_builder.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_bicep_builder.py similarity index 100% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_bicep_builder.py rename to src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_bicep_builder.py diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_definition_folder_builder.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_definition_folder_builder.py new file mode 100644 index 00000000000..801d86c7304 --- /dev/null +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_definiton_folder_builder/test_definition_folder_builder.py @@ -0,0 +1,52 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +import json +from pathlib import Path +from unittest import TestCase +from unittest.mock import MagicMock, patch + +from azext_aosm.definition_folder.builder.definition_folder_builder import DefinitionFolderBuilder + + +class TestDefinitionFolderBuilder(TestCase): + """Test the definition folder builder.""" + + @patch("pathlib.Path.write_text") + @patch("pathlib.Path.mkdir") + def test_add_elements_and_write(self, mock_mkdir, mock_write_text): + """Test adding elements and writing the definition folder.""" + + # Create some mocks to act as definition elements. + element_1 = MagicMock() + element_1.path = Path("/some/folder/element_1") + element_1.only_delete_on_clean = False + element_2 = MagicMock() + element_2.path = Path("/some/folder/element_2") + element_2.only_delete_on_clean = True + + # Create a definition folder builder. + definition_folder_builder = DefinitionFolderBuilder(Path("/some/folder")) + + # Add the elements to the definition folder builder. + definition_folder_builder.add_element(element_1) + definition_folder_builder.add_element(element_2) + + # Write the definition folder. + definition_folder_builder.write() + + # Check that the elements were written to disk. + mock_mkdir.assert_called_once() + element_1.write.assert_called_once() + element_2.write.assert_called_once() + + # Check that the index.json file was written to disk. + expected_params = [{"name": "element_1", + "type": "artifact", + "only_delete_on_clean": False }, + {"name": "element_2", + "type": "artifact", + "only_delete_on_clean": True}] + mock_write_text.assert_called_once_with(json.dumps(expected_params, indent=4)) + diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_cnf_generate_config.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_cnf_generate_config.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_core_vnf_generate_config.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_core_vnf_generate_config.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nexus_vnf_generate_config.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nexus_vnf_generate_config.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nsd_generate_config.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_generate_config/test_nsd_generate_config.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_arm_template_input.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_arm_template_input.py new file mode 100644 index 00000000000..4fc37747237 --- /dev/null +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_arm_template_input.py @@ -0,0 +1,170 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +import logging +import os +import sys +from unittest import TestCase +from unittest.mock import mock_open, patch + +from azext_aosm.inputs.arm_template_input import ArmTemplateInput + +code_directory = os.path.dirname(__file__) +parent_directory = os.path.abspath(os.path.join(code_directory, "../..")) +arm_template_path = os.path.join(parent_directory, "mock_arm_templates", "simple-template.json") +no_params_template_path = os.path.join(parent_directory, "mock_arm_templates", "no-params-template.json") + +class TestARMTemplateInput(TestCase): + """Test the ARMTempalteInput class.""" + + def setUp(self): + # Prints out info logs in console if fails + logging.basicConfig(level=logging.INFO, stream=sys.stdout) + self.arm_input = ArmTemplateInput( + artifact_name="test-artifact-name", + artifact_version="1.1.1", + template_path=arm_template_path, + default_config=None + ) + + def test_get_defaults_is_none(self): + """Test ARM template input when default config is None""" + arm_template_input = self.arm_input + + # Test when default_config is None + arm_template_input.default_config = None + defaults = arm_template_input.get_defaults() + self.assertEqual(defaults, {}) + + def test_get_defaults_is_empty_dict(self): + """Test ARM template input when default config is {}""" + arm_template_input = self.arm_input + # Test when default_config is an empty dictionary + arm_template_input.default_config = {} + defaults = arm_template_input.get_defaults() + self.assertEqual(defaults, {}) + + def test_get_defaults_with_config(self): + """Test ARM template input when default config provided""" + arm_template_input = self.arm_input + # Test when default_config has some values + arm_template_input.default_config = { + "param1": "value1", + "param2": "value2" + } + defaults = arm_template_input.get_defaults() + self.assertEqual(defaults, { + "param1": "value1", + "param2": "value2" + }) + + def test_get_schema_with_params(self): + """Test getting the schema for the ARM template input.""" + schema = self.arm_input.get_schema() + expected_schema = { + '$schema': 'https://json-schema.org/draft-07/schema#', + 'properties': {'location': {'type': 'string'}}, + 'required': [], + 'type': 'object' + } + print("SCHEMA", schema) + self.assertEqual(schema, expected_schema) + + @patch("builtins.open", mock_open( + read_data='{"$schema": "#", "resources": { } }')) + def test_get_schema_no_parameters(self): + """Test getting the schema for the ARM template input when no parameters are found.""" + + no_params_arm_input = ArmTemplateInput( + artifact_name="test-artifact-name", + artifact_version="1.1.1", + template_path=no_params_template_path, + default_config=None + ) + # Assert logger warning when no parameters in file + with self.assertLogs(level='WARNING'): + schema = self.arm_input.get_schema() + expected_schema = { + '$schema': 'https://json-schema.org/draft-07/schema#', + 'properties': {}, + 'required': [], + 'type': 'object' + } + # Assert outputted schema is base schema with empty properties + self.assertEqual(schema, expected_schema) + + def test_generate_schema_from_params_with_default_values(self): + """ Test _generate_schema_from_params for ARM template input. + With default values, which mean no required params + """ + schema = { + "properties": {}, + "required": [] + } + data = { + "test": { + "type": "string", + "defaultValue": "test" + } + } + # pylint: disable=protected-access + self.arm_input._generate_schema_from_params(schema, data) + + expected_schema = { + 'properties': + {'test': {'type': 'string'}}, + 'required': []} + + self.assertEqual(schema, expected_schema) + + def test_generate_schema_from_params_with_no_default_values(self): + """ Test _generate_schema_from_params for ARM template input. + Without default values, so they should be added to required properties + """ + schema = { + "properties": {}, + "required": [] + } + data = { + "test": { + "type": "string" + } + } + # pylint: disable=protected-access + self.arm_input._generate_schema_from_params(schema, data) + expected_schema = {'properties': {'test': {'type': 'string'}}, 'required': ['test']} + self.assertEqual(schema, expected_schema) + + def test_generate_schema_from_params_nested_properties(self): + """ Test _generate_schema_from_params for ARM template input. + With an object in the template, so we expect this to be called recursively + """ + schema = { + "properties": {}, + "required": [] + } + data = { + "test": { + "type": "string" + }, + "vmImageRepositoryCredentials": { + "type": "object", + "metadata": { + "description": "Credentials used to login to the image repository." + } + } + } + # pylint: disable=protected-access + self.arm_input._generate_schema_from_params(schema, data) + + # We expect vmImageRepositoryCredentials to be required and to have a nested schema + expected_schema = {'properties': + {'test': {'type': 'string'}, + 'vmImageRepositoryCredentials': { + "type": "object", + "properties": {}, + "required": []} + }, + 'required': ['test', 'vmImageRepositoryCredentials']} + self.assertEqual(schema, expected_schema) diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_input.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_helm_chart_input.py similarity index 69% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_input.py rename to src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_helm_chart_input.py index b492dff9b92..d4a823cff55 100644 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_input.py +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_inputs/test_helm_chart_input.py @@ -7,15 +7,17 @@ import sys from pathlib import Path from unittest import TestCase - +import tempfile +import json from azext_aosm.common.exceptions import ( DefaultValuesNotFoundError, TemplateValidationError, + SchemaGetOrGenerateError ) from azext_aosm.inputs.helm_chart_input import HelmChartInput code_directory = os.path.dirname(__file__) -parent_directory = os.path.abspath(os.path.join(code_directory, "..")) +parent_directory = os.path.abspath(os.path.join(code_directory, "../..")) helm_charts_directory = os.path.join(parent_directory, "mock_cnf", "helm-charts") VALID_CHART_NAME = "nf-agent-cnf" @@ -26,6 +28,7 @@ class TestHelmChartInput(TestCase): """Test the HelmChartInput class.""" def setUp(self): + # Prints out info logs in console if fails logging.basicConfig(level=logging.INFO, stream=sys.stdout) def test_validate_template_valid_chart(self): @@ -108,3 +111,42 @@ def test_validate_invalid_values(self): with self.assertRaises(DefaultValuesNotFoundError): helm_chart_input.validate_values() + + def test_get_schema(self): + """Test retrieving the schema for the Helm chart.""" + self.temp_dir = tempfile.TemporaryDirectory() + self.chart_path = Path(self.temp_dir.name) + + with open(self.chart_path / "Chart.yaml", "w") as f: + f.write("name: test-chart\nversion: 1.0.0") + + helm_chart_input = HelmChartInput( + artifact_name="test-schema", + artifact_version="1.0.0", + chart_path=self.chart_path, + ) + + # Test case when values.schema.json exists in the chart. + with open(self.chart_path / "values.schema.json", "w") as f: + json.dump({"key": "value"}, f) + schema = helm_chart_input.get_schema() + self.assertEqual(schema, {"key": "value"}) + + # Test case when values.schema.json does not exist in the chart. + os.remove(self.chart_path / "values.schema.json") + with open(self.chart_path / "values.yaml", "w") as f: + f.write("key: value") + schema = helm_chart_input.get_schema() + expected_schema = { + "type": "object", + "properties": {"key": {"type": "string"}}, + "required": ["key"], + } + self.assertEqual(schema, expected_schema) + + # Test case when neither values.schema.json nor values.yaml exist in the chart. + os.remove(self.chart_path / "values.yaml") + with self.assertRaises(SchemaGetOrGenerateError): + helm_chart_input.get_schema() + + self.temp_dir.cleanup() diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_core_arm_processor.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_core_arm_processor.py new file mode 100644 index 00000000000..80d5ded87d8 --- /dev/null +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_core_arm_processor.py @@ -0,0 +1,173 @@ +import os +import logging +import sys +import json +from unittest import TestCase +from unittest.mock import MagicMock +from azext_aosm.build_processors.arm_processor import AzureCoreArmBuildProcessor +from azext_aosm.inputs.arm_template_input import ArmTemplateInput +from azext_aosm.vendored_sdks.models import ( + AzureCoreNetworkFunctionArmTemplateApplication, + ApplicationEnablement, ArmResourceDefinitionResourceElementTemplate, + ArmResourceDefinitionResourceElementTemplateDetails, + ArmTemplateArtifactProfile, + ArmTemplateMappingRuleProfile, + AzureCoreArmTemplateArtifactProfile, + NSDArtifactProfile, + TemplateType, + AzureCoreArmTemplateDeployMappingRuleProfile, + DependsOnProfile, + ManifestArtifactFormat, + ReferencedResource, +) +from azext_aosm.common.constants import TEMPLATE_PARAMETERS_FILENAME +from azext_aosm.definition_folder.builder.local_file_builder import LocalFileBuilder +from azext_aosm.common.artifact import LocalFileACRArtifact + +code_directory = os.path.dirname(__file__) +parent_directory = os.path.abspath(os.path.join(code_directory, "../..")) +mock_vnf_directory = os.path.join(parent_directory, "mock_core_vnf") + + +class AzureCoreArmProcessorTest(TestCase): + """Class to test AzureCore ARM Processor functionality""" + + def setUp(self): + logging.basicConfig(level=logging.INFO, stream=sys.stdout) + mock_arm_template_path = os.path.join(mock_vnf_directory, "ubuntu-template.json") + self.core_arm_input = ArmTemplateInput( + artifact_name="test-artifact-name", + artifact_version="1.1.1", + template_path=mock_arm_template_path, + default_config=None + ) + self.processor = AzureCoreArmBuildProcessor("test-name", self.core_arm_input) + + def test_get_artifact_manifest_list(self): + """Test get artifact manifest list for Azure Core arm processor.""" + manifest_list = self.processor.get_artifact_manifest_list() + mock_manifest_artifact_format = ManifestArtifactFormat( + artifact_name="test-artifact-name", + artifact_type="ArmTemplate", + artifact_version="1.1.1", + ) + self.assertEqual(len(manifest_list), 1) + self.assertIsInstance(manifest_list[0], ManifestArtifactFormat) + self.assertEqual(manifest_list[0], mock_manifest_artifact_format) + + def test_artifact_details(self): + """Test get artifact details for Azure Core arm processor.""" + artifact_details = self.processor.get_artifact_details() + mock_arm_template_path = os.path.join(mock_vnf_directory, "ubuntu-template.json") + mock_artifact = [LocalFileACRArtifact( + artifact_name="test-artifact-name", + artifact_type="ArmTemplate", + artifact_version="1.1.1", + file_path=mock_arm_template_path, + )] + + # Testing each individial part of artifact are equal, + # as two artifacts objects are never equal, even if they contain the same content + self.assertEqual(artifact_details[0][0].artifact_name, mock_artifact[0].artifact_name) + self.assertEqual(artifact_details[0][0].artifact_version, mock_artifact[0].artifact_version) + self.assertEqual(artifact_details[0][0].artifact_type, mock_artifact[0].artifact_type) + self.assertEqual(artifact_details[0][0].file_path, mock_artifact[0].file_path) + # Ensure no list of LocalFileBuilders is returned, as this is only for NSDs + self.assertEqual(artifact_details[1], []) + assert True + + def test_generate_nf_application(self): + """Test generate nf application for Azure Core ARM Processor.""" + # Check type is correct, other functionality is tested in appropriate functions + # (such as test_generate_artifact_profile) + nf_application = self.processor.generate_nf_application() + self.assertIsInstance(nf_application, AzureCoreNetworkFunctionArmTemplateApplication) + + def test_generate_resource_element_template(self): + """Test generate RET for Azure Core ARM Processor""" + result = self.processor.generate_resource_element_template() + + # Assert the expected output + expected_template = ArmResourceDefinitionResourceElementTemplateDetails( + name="test-name", + depends_on_profile=DependsOnProfile( + install_depends_on=[], uninstall_depends_on=[], update_depends_on=[] + ), + configuration=ArmResourceDefinitionResourceElementTemplate( + template_type=TemplateType.ARM_TEMPLATE.value, + parameter_values=json.dumps({}), + artifact_profile=NSDArtifactProfile( + artifact_store_reference=ReferencedResource(id=""), + artifact_name=self.processor.input_artifact.artifact_name, + artifact_version=self.processor.input_artifact.artifact_version, + ), + ), + ) + # Assert each parameter equal + self.assertEqual(result.name, expected_template.name) + self.assertEqual(result.depends_on_profile, expected_template.depends_on_profile) + self.assertEqual(result.configuration.artifact_profile, + expected_template.configuration.artifact_profile) + + def test_generate_parameters_file(self): + """ Test generate parameters file for Azure Core ARM Processor""" + # Mock private function + # (generate mapping rule profile is tested elsewhere) + mapping_rule_profile = MagicMock() + mock_params = '{"param1": "value1", "param2": "value2"}' + mapping_rule_profile.template_mapping_rule_profile.template_parameters = mock_params + self.processor._generate_mapping_rule_profile = MagicMock(return_value=mapping_rule_profile) + + parameters_file = self.processor.generate_parameters_file() + + # Assert the expected behaviour + expected_params = { + "param1": "value1", + "param2": "value2" + } + expected_json = json.dumps(expected_params, indent=4) + + # Assert the contents + self.assertEqual(parameters_file.file_content, expected_json) + # Assert name of the file includes + # (We want to know that in the instance of Azure Core ARM Templates, + # we are creating template parameters) + assert TEMPLATE_PARAMETERS_FILENAME in str(parameters_file.path) + + # Assert the type is LocalFileBuilder + self.assertIsInstance(parameters_file, LocalFileBuilder) + # Assert that the necessary methods were called + self.processor._generate_mapping_rule_profile.assert_called_once() + + def test_generate_mapping_rule_profile(self): + """ Test generate artifact profile returned correctly with generate_nf_application.""" + nf_application = self.processor.generate_nf_application() + mock_template_params = json.dumps({ + "subnetName": "{deployParameters.test-name.subnetName}", + "virtualNetworkId": "{deployParameters.test-name.virtualNetworkId}", + "sshPublicKeyAdmin": "{deployParameters.test-name.sshPublicKeyAdmin}", + "imageName": "{deployParameters.test-name.imageName}" + }) + expected_arm_mapping_profile = ArmTemplateMappingRuleProfile( + template_parameters=mock_template_params) + expected_nexus_arm_mapping_profile = AzureCoreArmTemplateDeployMappingRuleProfile( + application_enablement=ApplicationEnablement.ENABLED, + template_mapping_rule_profile=expected_arm_mapping_profile, + ) + self.assertEqual(nf_application.deploy_parameters_mapping_rule_profile, + expected_nexus_arm_mapping_profile) + self.assertIsInstance(nf_application.deploy_parameters_mapping_rule_profile, + AzureCoreArmTemplateDeployMappingRuleProfile) + + def test_generate_artifact_profile(self): + """ Test generate artifact profile returned correctly with generate_nf_application.""" + + nf_application = self.processor.generate_nf_application() + expected_arm_artifact_profile = ArmTemplateArtifactProfile( + template_name="test-artifact-name", template_version="1.1.1") + expected_nexus_arm_artifact_profile = AzureCoreArmTemplateArtifactProfile( + artifact_store=ReferencedResource(id=""), + template_artifact_profile=expected_arm_artifact_profile + ) + self.assertEqual(nf_application.artifact_profile, expected_nexus_arm_artifact_profile) + self.assertIsInstance(nf_application.artifact_profile, AzureCoreArmTemplateArtifactProfile) diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_processor.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_helm_chart_processor.py similarity index 99% rename from src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_processor.py rename to src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_helm_chart_processor.py index 83873e3a34e..ac9232a96e1 100644 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_helm_chart_processor.py +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_helm_chart_processor.py @@ -6,7 +6,7 @@ from azext_aosm.build_processors.helm_chart_processor import HelmChartProcessor code_directory = os.path.dirname(__file__) -parent_directory = os.path.abspath(os.path.join(code_directory, "..")) +parent_directory = os.path.abspath(os.path.join(code_directory, "../..")) mock_cnf_directory = os.path.join(parent_directory, "mock_cnf") HELM_TEMPLATE_MOCK_OUTPUT_FILE = "nf-agent-cnf-helm_template_output.yaml" diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_arm_processor.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_arm_processor.py index 78b08111e63..baa1c8785ec 100644 --- a/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_arm_processor.py +++ b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_arm_processor.py @@ -1,24 +1,173 @@ +import os +import logging +import sys +import json from unittest import TestCase -from unittest.mock import patch, MagicMock -from pathlib import Path -from typing import List +from unittest.mock import MagicMock from azext_aosm.build_processors.arm_processor import NexusArmBuildProcessor from azext_aosm.inputs.arm_template_input import ArmTemplateInput - -from azext_aosm.cli_handlers.onboarding_nexus_vnf_handler import OnboardingNexusVNFCLIHandler -from azext_aosm.definition_folder.builder.artifact_builder import ArtifactDefinitionElementBuilder -from azext_aosm.definition_folder.builder.bicep_builder import BicepDefinitionElementBuilder +from azext_aosm.vendored_sdks.models import ( + AzureOperatorNexusNetworkFunctionArmTemplateApplication, + ApplicationEnablement, ArmResourceDefinitionResourceElementTemplate, + ArmResourceDefinitionResourceElementTemplateDetails, + ArmTemplateArtifactProfile, + ArmTemplateMappingRuleProfile, + NSDArtifactProfile, + TemplateType, + AzureOperatorNexusArmTemplateDeployMappingRuleProfile, + AzureOperatorNexusArmTemplateArtifactProfile, + DependsOnProfile, + ManifestArtifactFormat, + ReferencedResource, +) from azext_aosm.definition_folder.builder.local_file_builder import LocalFileBuilder -from azext_aosm.common.constants import VNF_OUTPUT_FOLDER_FILENAME, ARTIFACT_LIST_FILENAME +from azext_aosm.common.artifact import LocalFileACRArtifact +from azext_aosm.common.constants import TEMPLATE_PARAMETERS_FILENAME +code_directory = os.path.dirname(__file__) +parent_directory = os.path.abspath(os.path.join(code_directory, "../..")) +mock_vnf_directory = os.path.join(parent_directory, "mock_nexus_vnf") -class NexusArmProcessorTest(TestCase): +class NexusArmProcessorTest(TestCase): + """Class to test Nexus ARM Processor functionality""" def setUp(self): - nexus_arm_input = ArmTemplateInput( + logging.basicConfig(level=logging.INFO, stream=sys.stdout) + mock_arm_template_path = os.path.join(mock_vnf_directory, "ubuntu-template.json") + self.nexus_arm_input = ArmTemplateInput( artifact_name="test-artifact-name", artifact_version="1.1.1", - template_path="", + template_path=mock_arm_template_path, default_config=None ) - self.processor = NexusArmBuildProcessor() + self.processor = NexusArmBuildProcessor("test-name", self.nexus_arm_input) + + def test_get_artifact_manifest_list(self): + """Test get artifact manifest list for nexus arm processor.""" + manifest_list = self.processor.get_artifact_manifest_list() + mock_manifest_artifact_format = ManifestArtifactFormat( + artifact_name="test-artifact-name", + artifact_type="ArmTemplate", + artifact_version="1.1.1", + ) + self.assertEqual(len(manifest_list), 1) + self.assertIsInstance(manifest_list[0], ManifestArtifactFormat) + self.assertEqual(manifest_list[0], mock_manifest_artifact_format) + assert True + + def test_artifact_details(self): + """Test get artifact details for nexus arm processor.""" + artifact_details = self.processor.get_artifact_details() + mock_arm_template_path = os.path.join(mock_vnf_directory, "ubuntu-template.json") + mock_artifact = [LocalFileACRArtifact( + artifact_name="test-artifact-name", + artifact_type="ArmTemplate", + artifact_version="1.1.1", + file_path=mock_arm_template_path, + )] + + # Ensure no list of LocalFileBuilders is returned, as this is only for NSDs + self.assertEqual(artifact_details[0][0].artifact_name, mock_artifact[0].artifact_name) + self.assertEqual(artifact_details[0][0].artifact_version, mock_artifact[0].artifact_version) + self.assertEqual(artifact_details[0][0].artifact_type, mock_artifact[0].artifact_type) + self.assertEqual(artifact_details[0][0].file_path, mock_artifact[0].file_path) + self.assertEqual(artifact_details[1], []) + assert True + + def test_generate_nf_application(self): + """Test generate nf application for nexus arm processor.""" + # Check type is correct, other functionality is tested in appropriate functions + # (such as test_generate_artifact_profile) + nf_application = self.processor.generate_nf_application() + self.assertIsInstance(nf_application, + AzureOperatorNexusNetworkFunctionArmTemplateApplication) + + def test_generate_resource_element_template(self): + """Test generate RET for Nexus ARM Processor""" + result = self.processor.generate_resource_element_template() + + # Assert the expected output + expected_template = ArmResourceDefinitionResourceElementTemplateDetails( + name="test-name", + depends_on_profile=DependsOnProfile( + install_depends_on=[], uninstall_depends_on=[], update_depends_on=[] + ), + configuration=ArmResourceDefinitionResourceElementTemplate( + template_type=TemplateType.ARM_TEMPLATE.value, + parameter_values=json.dumps({}), + artifact_profile=NSDArtifactProfile( + artifact_store_reference=ReferencedResource(id=""), + artifact_name=self.processor.input_artifact.artifact_name, + artifact_version=self.processor.input_artifact.artifact_version, + ), + ), + ) + # Assert each parameter equal + self.assertEqual(result.name, expected_template.name) + self.assertEqual(result.depends_on_profile, expected_template.depends_on_profile) + self.assertEqual(result.configuration.artifact_profile, + expected_template.configuration.artifact_profile) + + def test_generate_parameters_file(self): + """ Test generate parameters file for Nexus ARM Processor""" + + # Mock private function + # (generate mapping rule profile is tested elsewhere) + mapping_rule_profile = MagicMock() + mock_params = '{"param1": "value1", "param2": "value2"}' + mapping_rule_profile.template_mapping_rule_profile.template_parameters = mock_params + self.processor._generate_mapping_rule_profile = MagicMock(return_value=mapping_rule_profile) + + parameters_file = self.processor.generate_parameters_file() + + # Assert the expected behaviour + expected_params = { + "param1": "value1", + "param2": "value2" + } + expected_json = json.dumps(expected_params, indent=4) + + # Assert the contents + self.assertEqual(parameters_file.file_content, expected_json) + # Assert name of the file includes templateParameters + # (We want to know that in the instance of Nexus ARM Templates, + # we are creating template parameters) + assert TEMPLATE_PARAMETERS_FILENAME in str(parameters_file.path) + # Assert the type is LocalFileBuilder + self.assertIsInstance(parameters_file, LocalFileBuilder) + # Assert that the necessary methods were called + self.processor._generate_mapping_rule_profile.assert_called_once() + + def test_generate_mapping_rule_profile(self): + """ Test generate artifact profile returned correctly with generate_nf_application.""" + nf_application = self.processor.generate_nf_application() + mock_template_params = json.dumps({ + "subnetName": "{deployParameters.test-name.subnetName}", + "virtualNetworkId": "{deployParameters.test-name.virtualNetworkId}", + "sshPublicKeyAdmin": "{deployParameters.test-name.sshPublicKeyAdmin}", + "imageName": "{deployParameters.test-name.imageName}" + }) + expected_arm_mapping_profile = ArmTemplateMappingRuleProfile( + template_parameters=mock_template_params) + expected_nexus_arm_mapping_profile = AzureOperatorNexusArmTemplateDeployMappingRuleProfile( + application_enablement=ApplicationEnablement.ENABLED, + template_mapping_rule_profile=expected_arm_mapping_profile, + ) + self.assertEqual(nf_application.deploy_parameters_mapping_rule_profile, + expected_nexus_arm_mapping_profile) + self.assertIsInstance(nf_application.deploy_parameters_mapping_rule_profile, + AzureOperatorNexusArmTemplateDeployMappingRuleProfile) + + def test_generate_artifact_profile(self): + """ Test generate artifact profile returned correctly with generate_nf_application.""" + + nf_application = self.processor.generate_nf_application() + expected_arm_artifact_profile = ArmTemplateArtifactProfile( + template_name="test-artifact-name", template_version="1.1.1") + expected_nexus_arm_artifact_profile = AzureOperatorNexusArmTemplateArtifactProfile( + artifact_store=ReferencedResource(id=""), + template_artifact_profile=expected_arm_artifact_profile + ) + self.assertEqual(nf_application.artifact_profile, expected_nexus_arm_artifact_profile) + self.assertIsInstance(nf_application.artifact_profile, + AzureOperatorNexusArmTemplateArtifactProfile) diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_image_processor.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_nexus_image_processor.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_vhd_processor.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_processors/test_vhd_processor.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/aosm/azext_aosm/tests/latest/unit_test/test_utils.py b/src/aosm/azext_aosm/tests/latest/unit_test/test_utils.py new file mode 100644 index 00000000000..e69de29bb2d